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

[01/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 0093e26)

Repository: lucene-solr
Updated Branches:
  refs/heads/branch_6_0 88789aa6b -> 0a1951bef
  refs/heads/branch_6x d7ee7c661 -> 3a31a8c76


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoBBoxTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoBBoxTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoBBoxTest.java
new file mode 100755
index 0000000..f5a148f
--- /dev/null
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoBBoxTest.java
@@ -0,0 +1,364 @@
+/*
+ * 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.spatial3d.geom;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class GeoBBoxTest {
+
+  protected final double DEGREES_TO_RADIANS = Math.PI / 180.0;
+
+  @Test
+  public void testBBoxDegenerate() {
+    GeoBBox box;
+    GeoConvexPolygon cp;
+    int relationship;
+    List<GeoPoint> points = new ArrayList<GeoPoint>();
+    points.add(new GeoPoint(PlanetModel.SPHERE, 24 * DEGREES_TO_RADIANS, -30 * DEGREES_TO_RADIANS));
+    points.add(new GeoPoint(PlanetModel.SPHERE, -11 * DEGREES_TO_RADIANS, 101 * DEGREES_TO_RADIANS));
+    points.add(new GeoPoint(PlanetModel.SPHERE, -49 * DEGREES_TO_RADIANS, -176 * DEGREES_TO_RADIANS));
+    GeoMembershipShape shape = GeoPolygonFactory.makeGeoPolygon(PlanetModel.SPHERE, points, 0);
+    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, -64 * DEGREES_TO_RADIANS, -64 * DEGREES_TO_RADIANS, -180 * DEGREES_TO_RADIANS, 180 * DEGREES_TO_RADIANS);
+    relationship = box.getRelationship(shape);
+    assertEquals(GeoArea.CONTAINS, relationship);
+    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, -61.85 * DEGREES_TO_RADIANS, -67.5 * DEGREES_TO_RADIANS, -180 * DEGREES_TO_RADIANS, -168.75 * DEGREES_TO_RADIANS);
+    //System.out.println("Shape = " + shape + " Rect = " + box);
+    relationship = box.getRelationship(shape);
+    assertEquals(GeoArea.CONTAINS, relationship);
+  }
+
+  @Test
+  public void testBBoxPointWithin() {
+    GeoBBox box;
+    GeoPoint gp;
+
+    // Standard normal Rect box, not crossing dateline
+    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, -1.0, 1.0);
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, 0.0);
+    assertTrue(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.1, 0.0);
+    assertFalse(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0);
+    assertFalse(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, 1.1);
+    assertFalse(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -1.1);
+    assertFalse(box.isWithin(gp));
+    assertEquals(0.1,box.computeOutsideDistance(DistanceStyle.ARC,gp),1e-2);
+    assertEquals(0.1,box.computeOutsideDistance(DistanceStyle.NORMAL,gp),1e-2);
+    assertEquals(0.1,box.computeOutsideDistance(DistanceStyle.NORMAL,gp),1e-2);
+
+    // Standard normal Rect box, crossing dateline
+    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, Math.PI - 1.0, -Math.PI + 1.0);
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -Math.PI);
+    assertTrue(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.1, -Math.PI);
+    assertFalse(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.5, -Math.PI);
+    assertFalse(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -Math.PI + 1.1);
+    assertFalse(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, (-Math.PI - 1.1) + Math.PI * 2.0);
+    assertFalse(box.isWithin(gp));
+
+    // Latitude zone rectangle
+    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, -Math.PI, Math.PI);
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -Math.PI);
+    assertTrue(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.1, -Math.PI);
+    assertFalse(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.5, -Math.PI);
+    assertFalse(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -Math.PI + 1.1);
+    assertTrue(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, (-Math.PI - 1.1) + Math.PI * 2.0);
+    assertTrue(box.isWithin(gp));
+
+    // World
+    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, -Math.PI, Math.PI);
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -Math.PI);
+    assertTrue(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.1, -Math.PI);
+    assertTrue(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.5, -Math.PI);
+    assertTrue(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -Math.PI + 1.1);
+    assertTrue(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, (-Math.PI - 1.1) + Math.PI * 2.0);
+    assertTrue(box.isWithin(gp));
+
+  }
+
+  @Test
+  public void testBBoxExpand() {
+    GeoBBox box;
+    GeoPoint gp;
+    // Standard normal Rect box, not crossing dateline
+    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, -1.0, 1.0);
+    box = box.expand(0.1);
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, 0.0);
+    assertTrue(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.15, 0.0);
+    assertFalse(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.25 - 0.05, 0.0);
+    assertTrue(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.25 - 0.15, 0.0);
+    assertFalse(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -1.05);
+    assertTrue(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -1.15);
+    assertFalse(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, 1.05);
+    assertTrue(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, 1.15);
+    assertFalse(box.isWithin(gp));
+  }
+
+  @Test
+  public void testBBoxBounds() {
+    GeoBBox c;
+    LatLonBounds b;
+    XYZBounds xyzb;
+    GeoArea solid;
+    GeoPoint point;
+    int relationship;
+    
+    c= GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.7570958596622309, -0.7458670829264561, -0.9566079379002148, 1.4802570961901191);
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE,0.10922258701604912,0.1248184603754517,-0.8172414690802067,0.9959041483215542,-0.6136586624726926,0.6821740363641521);
+    point = new GeoPoint(PlanetModel.SPHERE, 0.3719987557178081, 1.4529582778845198);
+    assertTrue(c.isWithin(point));
+    assertTrue(solid.isWithin(point));
+    relationship = solid.getRelationship(c);
+    assertTrue(relationship == GeoArea.OVERLAPS || relationship == GeoArea.CONTAINS || relationship == GeoArea.WITHIN);
+
+    c= GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.006607096847842122, -0.002828135860810422, -0.0012934461873348349, 0.006727418645092394);
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE,0.9999995988328008,1.0000000002328306,-0.0012934708508166816,0.006727393021214471,-0.002828157275369464,0.006607074060760007);
+    point = new GeoPoint(PlanetModel.SPHERE, -5.236470872437899E-4, 3.992578692654256E-4);
+    assertTrue(c.isWithin(point));
+    assertTrue(solid.isWithin(point));
+    relationship = solid.getRelationship(c);
+    assertTrue(relationship == GeoArea.OVERLAPS || relationship == GeoArea.CONTAINS || relationship == GeoArea.WITHIN);
+    
+    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.25, -Math.PI * 0.25, -1.0, 1.0);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(-1.0, b.getLeftLongitude(), 0.000001);
+    assertEquals(1.0, b.getRightLongitude(), 0.000001);
+    assertEquals(-Math.PI * 0.25, b.getMinLatitude(), 0.000001);
+    assertEquals(Math.PI * 0.25, b.getMaxLatitude(), 0.000001);
+    assertEquals(0.382051, xyzb.getMinimumX(), 0.000001);
+    assertEquals(1.0, xyzb.getMaximumX(), 0.000001);
+    assertEquals(-0.841471, xyzb.getMinimumY(), 0.000001);
+    assertEquals(0.841471, xyzb.getMaximumY(), 0.000001);
+    assertEquals(-0.707107, xyzb.getMinimumZ(), 0.000001);
+    assertEquals(0.707107, xyzb.getMaximumZ(), 0.000001);
+    
+    GeoArea area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE,
+      xyzb.getMinimumX() - 2.0 * Vector.MINIMUM_RESOLUTION,
+      xyzb.getMaximumX() + 2.0 * Vector.MINIMUM_RESOLUTION,
+      xyzb.getMinimumY() - 2.0 * Vector.MINIMUM_RESOLUTION,
+      xyzb.getMaximumY() + 2.0 * Vector.MINIMUM_RESOLUTION,
+      xyzb.getMinimumZ() - 2.0 * Vector.MINIMUM_RESOLUTION,
+      xyzb.getMaximumZ() + 2.0 * Vector.MINIMUM_RESOLUTION);
+    assertEquals(GeoArea.WITHIN, area.getRelationship(c));
+
+    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, -1.0, 1.0);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(-1.0, b.getLeftLongitude(), 0.000001);
+    assertEquals(1.0, b.getRightLongitude(), 0.000001);
+    assertEquals(-Math.PI * 0.25, b.getMinLatitude(), 0.000001);
+    assertEquals(0.0, b.getMaxLatitude(), 0.000001);
+    assertEquals(0.382051, xyzb.getMinimumX(), 0.000001);
+    assertEquals(1.0, xyzb.getMaximumX(), 0.000001);
+    assertEquals(-0.841471, xyzb.getMinimumY(), 0.000001);
+    assertEquals(0.841471, xyzb.getMaximumY(), 0.000001);
+    assertEquals(-0.707107, xyzb.getMinimumZ(), 0.000001);
+    assertEquals(0.0, xyzb.getMaximumZ(), 0.000001);
+
+    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, 1.0, -1.0);
+
+    b = new LatLonBounds();
+    c.getBounds(b);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    assertTrue(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    //assertEquals(1.0,b.getLeftLongitude(),0.000001);
+    //assertEquals(-1.0,b.getRightLongitude(),0.000001);
+    assertEquals(-Math.PI * 0.25, b.getMinLatitude(), 0.000001);
+    assertEquals(0.0, b.getMaxLatitude(), 0.000001);
+    assertEquals(-1.0, xyzb.getMinimumX(), 0.000001);
+    assertEquals(0.540303, xyzb.getMaximumX(), 0.000001);
+    assertEquals(-1.0, xyzb.getMinimumY(), 0.000001);
+    assertEquals(1.0, xyzb.getMaximumY(), 0.000001);
+    assertEquals(-0.707107, xyzb.getMinimumZ(), 0.000001);
+    assertEquals(0.0, xyzb.getMaximumZ(), 0.000001);
+
+
+    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, -1.0, 1.0);
+
+    b = new LatLonBounds();
+    c.getBounds(b);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    assertTrue(b.checkNoLongitudeBound());
+    assertTrue(b.checkNoTopLatitudeBound());
+    assertTrue(b.checkNoBottomLatitudeBound());
+    //assertEquals(-1.0, b.getLeftLongitude(), 0.000001);
+    //assertEquals(1.0, b.getRightLongitude(), 0.000001);
+    assertEquals(0.0, xyzb.getMinimumX(), 0.000001);
+    assertEquals(1.0, xyzb.getMaximumX(), 0.000001);
+    assertEquals(-0.841471, xyzb.getMinimumY(), 0.000001);
+    assertEquals(0.841471, xyzb.getMaximumY(), 0.000001);
+    assertEquals(-1.0, xyzb.getMinimumZ(), 0.000001);
+    assertEquals(1.0, xyzb.getMaximumZ(), 0.000001);
+
+    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, 1.0, -1.0);
+
+    b = new LatLonBounds();
+    c.getBounds(b);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    assertTrue(b.checkNoLongitudeBound());
+    assertTrue(b.checkNoTopLatitudeBound());
+    assertTrue(b.checkNoBottomLatitudeBound());
+    //assertEquals(1.0,b.getLeftLongitude(),0.000001);
+    //assertEquals(-1.0,b.getRightLongitude(),0.000001);
+    assertEquals(-1.0, xyzb.getMinimumX(), 0.000001);
+    assertEquals(0.540303, xyzb.getMaximumX(), 0.000001);
+    assertEquals(-1.0, xyzb.getMinimumY(), 0.000001);
+    assertEquals(1.0, xyzb.getMaximumY(), 0.000001);
+    assertEquals(-1.0, xyzb.getMinimumZ(), 0.000001);
+    assertEquals(1.0, xyzb.getMaximumZ(), 0.000001);
+
+    // Check wide variants of rectangle and longitude slice
+
+    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, -Math.PI + 0.1, Math.PI - 0.1);
+
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertTrue(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    //assertEquals(-Math.PI+0.1,b.getLeftLongitude(),0.000001);
+    //assertEquals(Math.PI-0.1,b.getRightLongitude(),0.000001);
+    assertEquals(-Math.PI * 0.25, b.getMinLatitude(), 0.000001);
+    assertEquals(0.0, b.getMaxLatitude(), 0.000001);
+
+    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, Math.PI - 0.1, -Math.PI + 0.1);
+
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(Math.PI - 0.1, b.getLeftLongitude(), 0.000001);
+    assertEquals(-Math.PI + 0.1, b.getRightLongitude(), 0.000001);
+    assertEquals(-Math.PI * 0.25, b.getMinLatitude(), 0.000001);
+    assertEquals(0.0, b.getMaxLatitude(), 0.000001);
+
+    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, -Math.PI + 0.1, Math.PI - 0.1);
+
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertTrue(b.checkNoLongitudeBound());
+    assertTrue(b.checkNoTopLatitudeBound());
+    assertTrue(b.checkNoBottomLatitudeBound());
+    //assertEquals(-Math.PI+0.1,b.getLeftLongitude(),0.000001);
+    //assertEquals(Math.PI-0.1,b.getRightLongitude(),0.000001);
+
+    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, Math.PI - 0.1, -Math.PI + 0.1);
+
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertTrue(b.checkNoLongitudeBound());
+    assertTrue(b.checkNoTopLatitudeBound());
+    assertTrue(b.checkNoBottomLatitudeBound());
+    //assertEquals(Math.PI - 0.1, b.getLeftLongitude(), 0.000001);
+    //assertEquals(-Math.PI + 0.1, b.getRightLongitude(), 0.000001);
+
+    // Check latitude zone
+    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 1.0, -1.0, -Math.PI, Math.PI);
+
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertTrue(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(-1.0, b.getMinLatitude(), 0.000001);
+    assertEquals(1.0, b.getMaxLatitude(), 0.000001);
+
+    // Now, combine a few things to test the bounds object
+    GeoBBox c1;
+    GeoBBox c2;
+
+    c1 = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, -Math.PI, 0.0);
+    c2 = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, 0.0, Math.PI);
+
+    b = new LatLonBounds();
+    c1.getBounds(b);
+    c2.getBounds(b);
+    assertTrue(b.checkNoLongitudeBound());
+    assertTrue(b.checkNoTopLatitudeBound());
+    assertTrue(b.checkNoBottomLatitudeBound());
+
+    c1 = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, -Math.PI, 0.0);
+    c2 = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, 0.0, Math.PI * 0.5);
+
+    b = new LatLonBounds();
+    c1.getBounds(b);
+    c2.getBounds(b);
+    assertTrue(b.checkNoLongitudeBound());
+    assertTrue(b.checkNoTopLatitudeBound());
+    assertTrue(b.checkNoBottomLatitudeBound());
+    //assertEquals(-Math.PI,b.getLeftLongitude(),0.000001);
+    //assertEquals(Math.PI*0.5,b.getRightLongitude(),0.000001);
+
+    c1 = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, -Math.PI * 0.5, 0.0);
+    c2 = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, 0.0, Math.PI);
+
+    b = new LatLonBounds();
+    c1.getBounds(b);
+    c2.getBounds(b);
+    assertTrue(b.checkNoLongitudeBound());
+    assertTrue(b.checkNoTopLatitudeBound());
+    assertTrue(b.checkNoBottomLatitudeBound());
+    //assertEquals(-Math.PI * 0.5,b.getLeftLongitude(),0.000001);
+    //assertEquals(Math.PI,b.getRightLongitude(),0.000001);
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoCircleTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoCircleTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoCircleTest.java
new file mode 100755
index 0000000..186bf4c
--- /dev/null
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoCircleTest.java
@@ -0,0 +1,410 @@
+/*
+ * 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.spatial3d.geom;
+
+import org.apache.lucene.util.LuceneTestCase;
+import org.junit.Test;
+
+public class GeoCircleTest extends LuceneTestCase {
+
+  @Test
+  public void testCircleDistance() {
+    GeoCircle c;
+    GeoPoint gp;
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, -0.5, 0.1);
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
+    assertEquals(Double.MAX_VALUE, c.computeDistance(DistanceStyle.ARC,gp), 0.0);
+    assertEquals(Double.MAX_VALUE, c.computeDistance(DistanceStyle.NORMAL,gp), 0.0);
+    assertEquals(Double.MAX_VALUE, c.computeDistance(DistanceStyle.NORMAL,gp), 0.0);
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
+    assertEquals(0.0, c.computeDistance(DistanceStyle.ARC,gp), 0.000001);
+    assertEquals(0.0, c.computeDistance(DistanceStyle.NORMAL,gp), 0.000001);
+    assertEquals(0.0, c.computeDistance(DistanceStyle.NORMAL,gp), 0.000001);
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, -0.5);
+    assertEquals(0.05, c.computeDistance(DistanceStyle.ARC,gp), 0.000001);
+    assertEquals(0.049995, c.computeDistance(DistanceStyle.LINEAR,gp), 0.000001);
+    assertEquals(0.049979, c.computeDistance(DistanceStyle.NORMAL,gp), 0.000001);
+  }
+
+  @Test
+  public void testCircleFullWorld() {
+    GeoCircle c;
+    GeoPoint gp;
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, -0.5, Math.PI);
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.55);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.45);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.5, 0.0);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
+    assertTrue(c.isWithin(gp));
+    LatLonBounds b = new LatLonBounds();
+    c.getBounds(b);
+    assertTrue(b.checkNoLongitudeBound());
+    assertTrue(b.checkNoTopLatitudeBound());
+    assertTrue(b.checkNoBottomLatitudeBound());
+  }
+
+  @Test
+  public void testCirclePointWithin() {
+    GeoCircle c;
+    GeoPoint gp;
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, -0.5, 0.1);
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
+    assertFalse(c.isWithin(gp));
+    assertEquals(0.4,c.computeOutsideDistance(DistanceStyle.ARC,gp),1e-12);
+    assertEquals(0.12,c.computeOutsideDistance(DistanceStyle.NORMAL,gp),0.01);
+    assertEquals(0.4,c.computeOutsideDistance(DistanceStyle.LINEAR,gp),0.01);
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.55);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.45);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.5, 0.0);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
+    assertFalse(c.isWithin(gp));
+  }
+
+  @Test
+  public void testCircleBounds() {
+    GeoCircle c;
+    LatLonBounds b;
+    XYZBounds xyzb;
+    GeoArea area;
+    GeoPoint p1;
+    GeoPoint p2;
+    int relationship;
+
+    // ...
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84, -0.005931145568901605, -0.001942031539653079, 1.2991918568260272E-4);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84, 1.001098377143621, 1.001100011578687, -0.00207467080358696, -0.0018136665346280983, -0.006067808248760161, -0.005807683665759485);
+    p1 = new GeoPoint(PlanetModel.WGS84, -0.00591253844632244, -0.0020069187259065093);
+    p2 = new GeoPoint(1.001099185736782, -0.0020091272069679327, -0.005919118245803968);
+    assertTrue(c.isWithin(p1));
+    assertTrue(area.isWithin(p1));
+    relationship = area.getRelationship(c);
+    assertTrue(relationship != GeoArea.DISJOINT);
+
+    // Twelfth BKD discovered failure
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84,-0.00824379317765984,-0.0011677469001838581,0.0011530035396910402);
+    p1 = new GeoPoint(PlanetModel.WGS84,-0.006505092992723671,0.007654282718327381);
+    p2 = new GeoPoint(1.0010681673665647,0.007662608264336381,-0.006512324005914593);
+    assertTrue(!c.isWithin(p1));
+    assertTrue(!c.isWithin(p2));
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84, 
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    relationship = area.getRelationship(c);
+    assertTrue(relationship == GeoArea.OVERLAPS || relationship == GeoArea.WITHIN);
+    // Point is actually outside the bounds, and outside the shape
+    assertTrue(!area.isWithin(p1));
+    // Approximate point the same
+    assertTrue(!area.isWithin(p2));
+    
+    // Eleventh BKD discovered failure
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE,-0.004431288600558495,-0.003687846671278374,1.704543429364245E-8);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    //System.err.println(area);
+    relationship = area.getRelationship(c);
+    assertTrue(GeoArea.WITHIN == relationship || GeoArea.OVERLAPS == relationship);
+
+    // Tenth BKD discovered failure
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84,-0.0018829770647349636,-0.001969499061382591,1.3045439293158305E-5);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84, 
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    //System.err.println(area);
+    relationship = area.getRelationship(c);
+    assertTrue(GeoArea.WITHIN == relationship || GeoArea.OVERLAPS == relationship);
+
+    // Ninth BKD discovered failure
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE,-4.211990380885122E-5,-0.0022958453508173044,1.4318475623498535E-5);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    //System.err.println(area);
+    relationship = area.getRelationship(c);
+    assertTrue(GeoArea.WITHIN == relationship || GeoArea.OVERLAPS == relationship);
+    
+    // Eighth BKD discovered failure
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE,0.005321278689117842,-0.00216937368755372,1.5306034422500785E-4);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    //System.err.println(area);
+    relationship = area.getRelationship(c);
+    assertTrue(GeoArea.WITHIN == relationship || GeoArea.OVERLAPS == relationship);
+
+    // Seventh BKD discovered failure
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE,-0.0021627146783861745, -0.0017298167021592304,2.0818312293195752E-4);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    //System.err.println(area);
+    relationship = area.getRelationship(c);
+    assertTrue(GeoArea.WITHIN == relationship || GeoArea.OVERLAPS == relationship);
+
+    // Sixth BKD discovered failure
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84,-0.006450320645814321,0.004660694205115142,0.00489710732634323);
+    //xyzb = new XYZBounds();
+    //c.getBounds(xyzb);
+    //System.err.println("xmin="+xyzb.getMinimumX()+", xmax="+xyzb.getMaximumX()+",ymin="+xyzb.getMinimumY()+", ymax="+xyzb.getMaximumY()+",zmin="+xyzb.getMinimumZ()+", zmax="+xyzb.getMaximumZ());
+    //xmin=1.0010356621420726, xmax=1.0011141249179447,ymin=-2.5326643901354566E-4, ymax=0.009584741915757169,zmin=-0.011359874956269283, zmax=-0.0015549504447452225
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84,1.0010822580620098,1.0010945779732867,0.007079167343247293,0.007541006774427837,-0.0021855011220022575,-0.001896122718181518);
+    assertTrue(GeoArea.CONTAINS != area.getRelationship(c));
+    /*
+    p1 = new GeoPoint(1.0010893045436076,0.007380935180644008,-0.002140671370616495);
+    // This has a different bounding box, so we can't use it.
+    //p2 = new GeoPoint(PlanetModel.WGS84,-0.002164069780096702, 0.007505617500830066);
+    p2 = new GeoPoint(PlanetModel.WGS84,p1.getLatitude(),p1.getLongitude());
+    assertTrue(PlanetModel.WGS84.pointOnSurface(p2));
+    assertTrue(!c.isWithin(p2));
+    assertTrue(!area.isWithin(p2));
+    assertTrue(!c.isWithin(p1));
+    assertTrue(PlanetModel.WGS84.pointOnSurface(p1)); // This fails
+    assertTrue(!area.isWithin(p1)); // This fails
+    */
+    
+    // Fifth BKD discovered failure
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -0.004282454525970269, -1.6739831367422277E-4, 1.959639723134033E-6);
+    assertTrue(c.isWithin(c.getEdgePoints()[0]));
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE,
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    assertTrue(GeoArea.WITHIN == area.getRelationship(c) || GeoArea.OVERLAPS == area.getRelationship(c));
+    
+    // Fourth BKD discovered failure
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -0.0048795517261255, 0.004053904306995974, 5.93699764258874E-6);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE,
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    assertTrue(GeoArea.WITHIN == area.getRelationship(c) || GeoArea.OVERLAPS == area.getRelationship(c));
+    
+    // Yet another test case from BKD
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84, 0.006229478708446979, 0.005570196723795424, 3.840276763694387E-5);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84,
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    p1 = new GeoPoint(PlanetModel.WGS84, 0.006224927111830945, 0.005597367237251763);
+    p2 = new GeoPoint(1.0010836083810235, 0.005603490759433942, 0.006231850560862502);
+    assertTrue(PlanetModel.WGS84.pointOnSurface(p1));
+    //assertTrue(PlanetModel.WGS84.pointOnSurface(p2));
+    assertTrue(c.isWithin(p1));
+    assertTrue(c.isWithin(p2));
+    assertTrue(area.isWithin(p1));
+    assertTrue(area.isWithin(p2));
+    
+    // Another test case from BKD
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -0.005955031040627789, -0.0029274772647399153, 1.601488279374338E-5);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE,
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    
+    relationship = area.getRelationship(c);
+    assertTrue(relationship == GeoArea.WITHIN || relationship == GeoArea.OVERLAPS);
+    
+    // Test case from BKD
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -0.765816119338, 0.991848766844, 0.8153163226330487);
+    p1 = new GeoPoint(0.7692262265236023, -0.055089298115534646, -0.6365973465711254);
+    assertTrue(c.isWithin(p1));
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    assertTrue(p1.x >= xyzb.getMinimumX() && p1.x <= xyzb.getMaximumX());
+    assertTrue(p1.y >= xyzb.getMinimumY() && p1.y <= xyzb.getMaximumY());
+    assertTrue(p1.z >= xyzb.getMinimumZ() && p1.z <= xyzb.getMaximumZ());
+    
+    // Vertical circle cases
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, -0.5, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(-0.6, b.getLeftLongitude(), 0.000001);
+    assertEquals(-0.4, b.getRightLongitude(), 0.000001);
+    assertEquals(-0.1, b.getMinLatitude(), 0.000001);
+    assertEquals(0.1, b.getMaxLatitude(), 0.000001);
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, 0.5, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(0.4, b.getLeftLongitude(), 0.000001);
+    assertEquals(0.6, b.getRightLongitude(), 0.000001);
+    assertEquals(-0.1, b.getMinLatitude(), 0.000001);
+    assertEquals(0.1, b.getMaxLatitude(), 0.000001);
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(-0.1, b.getLeftLongitude(), 0.000001);
+    assertEquals(0.1, b.getRightLongitude(), 0.000001);
+    assertEquals(-0.1, b.getMinLatitude(), 0.000001);
+    assertEquals(0.1, b.getMaxLatitude(), 0.000001);
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, Math.PI, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(Math.PI - 0.1, b.getLeftLongitude(), 0.000001);
+    assertEquals(-Math.PI + 0.1, b.getRightLongitude(), 0.000001);
+    assertEquals(-0.1, b.getMinLatitude(), 0.000001);
+    assertEquals(0.1, b.getMaxLatitude(), 0.000001);
+    // Horizontal circle cases
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, Math.PI * 0.5, 0.0, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertTrue(b.checkNoLongitudeBound());
+    assertTrue(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(Math.PI * 0.5 - 0.1, b.getMinLatitude(), 0.000001);
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertTrue(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertTrue(b.checkNoBottomLatitudeBound());
+    assertEquals(-Math.PI * 0.5 + 0.1, b.getMaxLatitude(), 0.000001);
+
+    // Now do a somewhat tilted plane, facing different directions.
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, 0.0, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
+    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
+    assertEquals(-0.1, b.getLeftLongitude(), 0.00001);
+    assertEquals(0.1, b.getRightLongitude(), 0.00001);
+
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, Math.PI, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
+    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
+    assertEquals(Math.PI - 0.1, b.getLeftLongitude(), 0.00001);
+    assertEquals(-Math.PI + 0.1, b.getRightLongitude(), 0.00001);
+
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, Math.PI * 0.5, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
+    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
+    assertEquals(Math.PI * 0.5 - 0.1, b.getLeftLongitude(), 0.00001);
+    assertEquals(Math.PI * 0.5 + 0.1, b.getRightLongitude(), 0.00001);
+
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, -Math.PI * 0.5, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
+    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
+    assertEquals(-Math.PI * 0.5 - 0.1, b.getLeftLongitude(), 0.00001);
+    assertEquals(-Math.PI * 0.5 + 0.1, b.getRightLongitude(), 0.00001);
+
+    // Slightly tilted, PI/4 direction.
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, Math.PI * 0.25, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
+    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
+    assertEquals(Math.PI * 0.25 - 0.1, b.getLeftLongitude(), 0.00001);
+    assertEquals(Math.PI * 0.25 + 0.1, b.getRightLongitude(), 0.00001);
+
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, -Math.PI * 0.25, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
+    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
+    assertEquals(-Math.PI * 0.25 - 0.1, b.getLeftLongitude(), 0.00001);
+    assertEquals(-Math.PI * 0.25 + 0.1, b.getRightLongitude(), 0.00001);
+
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -0.01, Math.PI * 0.25, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(0.09, b.getMaxLatitude(), 0.000001);
+    assertEquals(-0.11, b.getMinLatitude(), 0.000001);
+    assertEquals(Math.PI * 0.25 - 0.1, b.getLeftLongitude(), 0.00001);
+    assertEquals(Math.PI * 0.25 + 0.1, b.getRightLongitude(), 0.00001);
+
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -0.01, -Math.PI * 0.25, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(0.09, b.getMaxLatitude(), 0.000001);
+    assertEquals(-0.11, b.getMinLatitude(), 0.000001);
+    assertEquals(-Math.PI * 0.25 - 0.1, b.getLeftLongitude(), 0.00001);
+    assertEquals(-Math.PI * 0.25 + 0.1, b.getRightLongitude(), 0.00001);
+
+    // Now do a somewhat tilted plane.
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, -0.5, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
+    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
+    assertEquals(-0.6, b.getLeftLongitude(), 0.00001);
+    assertEquals(-0.4, b.getRightLongitude(), 0.00001);
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoConvexPolygonTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoConvexPolygonTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoConvexPolygonTest.java
new file mode 100755
index 0000000..a6ca404
--- /dev/null
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoConvexPolygonTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.spatial3d.geom;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class GeoConvexPolygonTest {
+
+
+  @Test
+  public void testPolygonPointWithin() {
+    GeoConvexPolygon c;
+    GeoPoint gp;
+    c = new GeoConvexPolygon(PlanetModel.SPHERE, -0.1, -0.5);
+    c.addPoint(0.0, -0.6, false);
+    c.addPoint(0.1, -0.5, false);
+    c.addPoint(0.0, -0.4, false);
+    c.done(false);
+    // Sample some points within
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.55);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.45);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.05, -0.5);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, -0.5);
+    assertTrue(c.isWithin(gp));
+    // Sample some nearby points outside, and compute distance-to-shape for them as well
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.65);
+    assertFalse(c.isWithin(gp));
+    assertEquals(0.05,c.computeOutsideDistance(DistanceStyle.ARC,gp),1e-12);
+    assertEquals(0.05,c.computeOutsideDistance(DistanceStyle.NORMAL,gp),1e-3);
+    assertEquals(0.05,c.computeOutsideDistance(DistanceStyle.LINEAR,gp),1e-3);
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.35);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.15, -0.5);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.15, -0.5);
+    assertFalse(c.isWithin(gp));
+    // Random points outside
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.5, 0.0);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
+    assertFalse(c.isWithin(gp));
+  }
+
+  @Test
+  public void testPolygonBounds() {
+    GeoConvexPolygon c;
+    LatLonBounds b;
+
+    c = new GeoConvexPolygon(PlanetModel.SPHERE, -0.1, -0.5);
+    c.addPoint(0.0, -0.6, false);
+    c.addPoint(0.1, -0.5, false);
+    c.addPoint(0.0, -0.4, false);
+    c.done(false);
+
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(-0.6, b.getLeftLongitude(), 0.000001);
+    assertEquals(-0.4, b.getRightLongitude(), 0.000001);
+    assertEquals(-0.1, b.getMinLatitude(), 0.000001);
+    assertEquals(0.1, b.getMaxLatitude(), 0.000001);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoModelTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoModelTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoModelTest.java
new file mode 100644
index 0000000..d5fcbdd
--- /dev/null
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoModelTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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.spatial3d.geom;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test basic plane functionality.
+ */
+public class GeoModelTest {
+
+  protected final static PlanetModel scaledModel = new PlanetModel(1.2,1.5);
+  
+  @Test
+  public void testBasicCircle() {
+    // The point of this test is just to make sure nothing blows up doing normal things with a quite non-spherical model
+    // Make sure that the north pole is in the circle, and south pole isn't
+    final GeoPoint northPole = new GeoPoint(scaledModel, Math.PI * 0.5, 0.0);
+    final GeoPoint southPole = new GeoPoint(scaledModel, -Math.PI * 0.5, 0.0);
+    final GeoPoint point1 = new GeoPoint(scaledModel, Math.PI * 0.25, 0.0);
+    final GeoPoint point2 = new GeoPoint(scaledModel, Math.PI * 0.125, 0.0);
+    
+    GeoCircle circle = new GeoStandardCircle(scaledModel, Math.PI * 0.5, 0.0, 0.01);
+    assertTrue(circle.isWithin(northPole));
+    assertFalse(circle.isWithin(southPole));
+    assertFalse(circle.isWithin(point1));
+    LatLonBounds bounds;
+    bounds = new LatLonBounds();
+    circle.getBounds(bounds);
+    assertTrue(bounds.checkNoLongitudeBound());
+    assertTrue(bounds.checkNoTopLatitudeBound());
+    assertFalse(bounds.checkNoBottomLatitudeBound());
+    assertEquals(Math.PI * 0.5 - 0.01, bounds.getMinLatitude(), 0.01);
+
+    circle = new GeoStandardCircle(scaledModel, Math.PI * 0.25, 0.0, 0.01);
+    assertTrue(circle.isWithin(point1));
+    assertFalse(circle.isWithin(northPole));
+    assertFalse(circle.isWithin(southPole));
+    bounds = new LatLonBounds();
+    circle.getBounds(bounds);
+    assertFalse(bounds.checkNoTopLatitudeBound());
+    assertFalse(bounds.checkNoLongitudeBound());
+    assertFalse(bounds.checkNoBottomLatitudeBound());
+    assertEquals(Math.PI * 0.25 + 0.01, bounds.getMaxLatitude(), 0.00001);
+    assertEquals(Math.PI * 0.25 - 0.01, bounds.getMinLatitude(), 0.00001);
+    assertEquals(-0.0125, bounds.getLeftLongitude(), 0.0001);
+    assertEquals(0.0125, bounds.getRightLongitude(), 0.0001);
+
+    circle = new GeoStandardCircle(scaledModel, Math.PI * 0.125, 0.0, 0.01);
+    assertTrue(circle.isWithin(point2));
+    assertFalse(circle.isWithin(northPole));
+    assertFalse(circle.isWithin(southPole));
+    bounds = new LatLonBounds();
+    circle.getBounds(bounds);
+    assertFalse(bounds.checkNoLongitudeBound());
+    assertFalse(bounds.checkNoTopLatitudeBound());
+    assertFalse(bounds.checkNoBottomLatitudeBound());
+    // Symmetric, as expected
+    assertEquals(Math.PI * 0.125 - 0.01, bounds.getMinLatitude(), 0.00001);
+    assertEquals(Math.PI * 0.125 + 0.01, bounds.getMaxLatitude(), 0.00001);
+    assertEquals(-0.0089, bounds.getLeftLongitude(), 0.0001);
+    assertEquals(0.0089, bounds.getRightLongitude(), 0.0001);
+
+  }
+
+  @Test
+  public void testBasicRectangle() {
+    final GeoBBox bbox = GeoBBoxFactory.makeGeoBBox(scaledModel, 1.0, 0.0, 0.0, 1.0);
+    final GeoPoint insidePoint = new GeoPoint(scaledModel, 0.5, 0.5);
+    assertTrue(bbox.isWithin(insidePoint));
+    final GeoPoint topOutsidePoint = new GeoPoint(scaledModel, 1.01, 0.5);
+    assertFalse(bbox.isWithin(topOutsidePoint));
+    final GeoPoint bottomOutsidePoint = new GeoPoint(scaledModel, -0.01, 0.5);
+    assertFalse(bbox.isWithin(bottomOutsidePoint));
+    final GeoPoint leftOutsidePoint = new GeoPoint(scaledModel, 0.5, -0.01);
+    assertFalse(bbox.isWithin(leftOutsidePoint));
+    final GeoPoint rightOutsidePoint = new GeoPoint(scaledModel, 0.5, 1.01);
+    assertFalse(bbox.isWithin(rightOutsidePoint));
+    final LatLonBounds bounds = new LatLonBounds();
+    bbox.getBounds(bounds);
+    assertFalse(bounds.checkNoLongitudeBound());
+    assertFalse(bounds.checkNoTopLatitudeBound());
+    assertFalse(bounds.checkNoBottomLatitudeBound());
+    assertEquals(1.0, bounds.getMaxLatitude(), 0.00001);
+    assertEquals(0.0, bounds.getMinLatitude(), 0.00001);
+    assertEquals(1.0, bounds.getRightLongitude(), 0.00001);
+    assertEquals(0.0, bounds.getLeftLongitude(), 0.00001);
+  }
+  
+}
+
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPathTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPathTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPathTest.java
new file mode 100755
index 0000000..3746069
--- /dev/null
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPathTest.java
@@ -0,0 +1,270 @@
+/*
+ * 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.spatial3d.geom;
+
+import org.junit.Test;
+
+import static java.lang.Math.toRadians;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class GeoPathTest {
+
+  @Test
+  public void testPathDistance() {
+    // Start with a really simple case
+    GeoPath p;
+    GeoPoint gp;
+    p = new GeoPath(PlanetModel.SPHERE, 0.1);
+    p.addPoint(0.0, 0.0);
+    p.addPoint(0.0, 0.1);
+    p.addPoint(0.0, 0.2);
+    p.done();
+    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.5, 0.15);
+    assertEquals(Double.MAX_VALUE, p.computeDistance(DistanceStyle.ARC,gp), 0.0);
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, 0.15);
+    assertEquals(0.15 + 0.05, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.12);
+    assertEquals(0.12 + 0.0, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.15, 0.05);
+    assertEquals(Double.MAX_VALUE, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.25);
+    assertEquals(0.20 + 0.05, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.05);
+    assertEquals(0.0 + 0.05, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
+
+    // Compute path distances now
+    p = new GeoPath(PlanetModel.SPHERE, 0.1);
+    p.addPoint(0.0, 0.0);
+    p.addPoint(0.0, 0.1);
+    p.addPoint(0.0, 0.2);
+    p.done();
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, 0.15);
+    assertEquals(0.15 + 0.05, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.12);
+    assertEquals(0.12, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
+
+    // Now try a vertical path, and make sure distances are as expected
+    p = new GeoPath(PlanetModel.SPHERE, 0.1);
+    p.addPoint(-Math.PI * 0.25, -0.5);
+    p.addPoint(Math.PI * 0.25, -0.5);
+    p.done();
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
+    assertEquals(Double.MAX_VALUE, p.computeDistance(DistanceStyle.ARC,gp), 0.0);
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -1.0);
+    assertEquals(Double.MAX_VALUE, p.computeDistance(DistanceStyle.ARC,gp), 0.0);
+    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.25 + 0.05, -0.5);
+    assertEquals(Math.PI * 0.5 + 0.05, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
+    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.25 - 0.05, -0.5);
+    assertEquals(0.0 + 0.05, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
+  }
+
+  @Test
+  public void testPathPointWithin() {
+    // Tests whether we can properly detect whether a point is within a path or not
+    GeoPath p;
+    GeoPoint gp;
+    p = new GeoPath(PlanetModel.SPHERE, 0.1);
+    // Build a diagonal path crossing the equator
+    p.addPoint(-0.2, -0.2);
+    p.addPoint(0.2, 0.2);
+    p.done();
+    // Test points on the path
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.2, -0.2);
+    assertTrue(p.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
+    assertTrue(p.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.1, 0.1);
+    assertTrue(p.isWithin(gp));
+    // Test points off the path
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.2, 0.2);
+    assertFalse(p.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0);
+    assertFalse(p.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.2, -0.2);
+    assertFalse(p.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
+    assertFalse(p.isWithin(gp));
+    // Repeat the test, but across the terminator
+    p = new GeoPath(PlanetModel.SPHERE, 0.1);
+    // Build a diagonal path crossing the equator
+    p.addPoint(-0.2, Math.PI - 0.2);
+    p.addPoint(0.2, -Math.PI + 0.2);
+    p.done();
+    // Test points on the path
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.2, Math.PI - 0.2);
+    assertTrue(p.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
+    assertTrue(p.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.1, -Math.PI + 0.1);
+    assertTrue(p.isWithin(gp));
+    // Test points off the path
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.2, -Math.PI + 0.2);
+    assertFalse(p.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0);
+    assertFalse(p.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.2, Math.PI - 0.2);
+    assertFalse(p.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
+    assertFalse(p.isWithin(gp));
+
+  }
+
+  @Test
+  public void testGetRelationship() {
+    GeoArea rect;
+    GeoPath p;
+    GeoPath c;
+    GeoPoint point;
+    GeoPoint pointApprox;
+    int relationship;
+    GeoArea area;
+    PlanetModel planetModel;
+    
+    planetModel = new PlanetModel(1.151145876105594, 0.8488541238944061);
+    c = new GeoPath(planetModel, 0.008726646259971648);
+    c.addPoint(-0.6925658899376476, 0.6316613927914589);
+    c.addPoint(0.27828548161836364, 0.6785795524104564);
+    c.done();
+    point = new GeoPoint(planetModel,-0.49298555067758226, 0.9892440995026406);
+    pointApprox = new GeoPoint(0.5110940362119821, 0.7774603209946239, -0.49984312299556544);
+    area = GeoAreaFactory.makeGeoArea(planetModel, 0.49937141144985997, 0.5161765426256085, 0.3337218719537796,0.8544419570901649, -0.6347692823688085, 0.3069696588119369);
+    assertTrue(!c.isWithin(point));
+    
+    // Start by testing the basic kinds of relationship, increasing in order of difficulty.
+
+    p = new GeoPath(PlanetModel.SPHERE, 0.1);
+    p.addPoint(-0.3, -0.3);
+    p.addPoint(0.3, 0.3);
+    p.done();
+    // Easiest: The path is wholly contains the georect
+    rect = new GeoRectangle(PlanetModel.SPHERE, 0.05, -0.05, -0.05, 0.05);
+    assertEquals(GeoArea.CONTAINS, rect.getRelationship(p));
+    // Next easiest: Some endpoints of the rectangle are inside, and some are outside.
+    rect = new GeoRectangle(PlanetModel.SPHERE, 0.05, -0.05, -0.05, 0.5);
+    assertEquals(GeoArea.OVERLAPS, rect.getRelationship(p));
+    // Now, all points are outside, but the figures intersect
+    rect = new GeoRectangle(PlanetModel.SPHERE, 0.05, -0.05, -0.5, 0.5);
+    assertEquals(GeoArea.OVERLAPS, rect.getRelationship(p));
+    // Finally, all points are outside, and the figures *do not* intersect
+    rect = new GeoRectangle(PlanetModel.SPHERE, 0.5, -0.5, -0.5, 0.5);
+    assertEquals(GeoArea.WITHIN, rect.getRelationship(p));
+    // Check that segment edge overlap detection works
+    rect = new GeoRectangle(PlanetModel.SPHERE, 0.1, 0.0, -0.1, 0.0);
+    assertEquals(GeoArea.OVERLAPS, rect.getRelationship(p));
+    rect = new GeoRectangle(PlanetModel.SPHERE, 0.2, 0.1, -0.2, -0.1);
+    assertEquals(GeoArea.DISJOINT, rect.getRelationship(p));
+    // Check if overlap at endpoints behaves as expected next
+    rect = new GeoRectangle(PlanetModel.SPHERE, 0.5, -0.5, -0.5, -0.35);
+    assertEquals(GeoArea.OVERLAPS, rect.getRelationship(p));
+    rect = new GeoRectangle(PlanetModel.SPHERE, 0.5, -0.5, -0.5, -0.45);
+    assertEquals(GeoArea.DISJOINT, rect.getRelationship(p));
+
+  }
+
+  @Test
+  public void testPathBounds() {
+    GeoPath c;
+    LatLonBounds b;
+    XYZBounds xyzb;
+    GeoPoint point;
+    int relationship;
+    GeoArea area;
+    PlanetModel planetModel;
+    
+    planetModel = new PlanetModel(0.751521665790406,1.248478334209594);
+    c = new GeoPath(planetModel, 0.7504915783575618);
+    c.addPoint(0.10869761172400265, 0.08895880215465272);
+    c.addPoint(0.22467878641991612, 0.10972973084229565);
+    c.addPoint(-0.7398772468744732, -0.4465812941383364);
+    c.addPoint(-0.18462055300079366, -0.6713857796763727);
+    c.done();
+    point = new GeoPoint(planetModel,-0.626645355125733,-1.409304625439381);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(planetModel,
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    relationship = area.getRelationship(c);
+    assertTrue(relationship == GeoArea.WITHIN || relationship == GeoArea.OVERLAPS);
+    assertTrue(area.isWithin(point));
+    // No longer true due to fixed GeoPath waypoints.
+    //assertTrue(c.isWithin(point));
+    
+    c = new GeoPath(PlanetModel.WGS84, 0.6894050545377601);
+    c.addPoint(-0.0788176065762948, 0.9431251741731624);
+    c.addPoint(0.510387871458147, 0.5327078872484678);
+    c.addPoint(-0.5624521609859962, 1.5398841746888388);
+    c.addPoint(-0.5025171434638661, -0.5895998642788894);
+    c.done();
+    point = new GeoPoint(PlanetModel.WGS84, 0.023652082107211682, 0.023131910152748437);
+    //System.err.println("Point.x = "+point.x+"; point.y="+point.y+"; point.z="+point.z);
+    assertTrue(c.isWithin(point));
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84,
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    //System.err.println("minx="+xyzb.getMinimumX()+" maxx="+xyzb.getMaximumX()+" miny="+xyzb.getMinimumY()+" maxy="+xyzb.getMaximumY()+" minz="+xyzb.getMinimumZ()+" maxz="+xyzb.getMaximumZ());
+    //System.err.println("point.x="+point.x+" point.y="+point.y+" point.z="+point.z);
+    relationship = area.getRelationship(c);
+    assertTrue(relationship == GeoArea.WITHIN || relationship == GeoArea.OVERLAPS);
+    assertTrue(area.isWithin(point));
+    
+    c = new GeoPath(PlanetModel.WGS84, 0.7766715171374766);
+    c.addPoint(-0.2751718361148076, -0.7786721269011477);
+    c.addPoint(0.5728375851539309, -1.2700115736820465);
+    c.done();
+    point = new GeoPoint(PlanetModel.WGS84, -0.01580760332365284, -0.03956004622490505);
+    assertTrue(c.isWithin(point));
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84,
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    //System.err.println("minx="+xyzb.getMinimumX()+" maxx="+xyzb.getMaximumX()+" miny="+xyzb.getMinimumY()+" maxy="+xyzb.getMaximumY()+" minz="+xyzb.getMinimumZ()+" maxz="+xyzb.getMaximumZ());
+    //System.err.println("point.x="+point.x+" point.y="+point.y+" point.z="+point.z);
+    relationship = area.getRelationship(c);
+    assertTrue(relationship == GeoArea.WITHIN || relationship == GeoArea.OVERLAPS);
+    assertTrue(area.isWithin(point));
+
+    c = new GeoPath(PlanetModel.SPHERE, 0.1);
+    c.addPoint(-0.3, -0.3);
+    c.addPoint(0.3, 0.3);
+    c.done();
+
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(-0.4046919, b.getLeftLongitude(), 0.000001);
+    assertEquals(0.4046919, b.getRightLongitude(), 0.000001);
+    assertEquals(-0.3999999, b.getMinLatitude(), 0.000001);
+    assertEquals(0.3999999, b.getMaxLatitude(), 0.000001);
+
+  }
+
+  @Test
+  public void testCoLinear() {
+    // p1: (12,-90), p2: (11, -55), (129, -90)
+    GeoPath p = new GeoPath(PlanetModel.SPHERE, 0.1);
+    p.addPoint(toRadians(-90), toRadians(12));//south pole
+    p.addPoint(toRadians(-55), toRadians(11));
+    p.addPoint(toRadians(-90), toRadians(129));//south pole again
+    p.done();//at least test this doesn't bomb like it used too -- LUCENE-6520
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPointTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPointTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPointTest.java
new file mode 100644
index 0000000..ed17928
--- /dev/null
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPointTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.spatial3d.geom;
+
+import org.apache.lucene.util.LuceneTestCase;
+import org.junit.Test;
+
+import static com.carrotsearch.randomizedtesting.RandomizedTest.randomFloat;
+
+/**
+ * Test basic GeoPoint functionality.
+ */
+public class GeoPointTest extends LuceneTestCase {
+  static final double DEGREES_TO_RADIANS =  Math.PI / 180;
+
+  @Test
+  public void testConversion() {
+    testPointRoundTrip(PlanetModel.SPHERE, 90 * DEGREES_TO_RADIANS, 0, 1e-6);
+    testPointRoundTrip(PlanetModel.SPHERE, -90 * DEGREES_TO_RADIANS, 0, 1e-6);
+    testPointRoundTrip(PlanetModel.WGS84, 90 * DEGREES_TO_RADIANS, 0, 1e-6);
+    testPointRoundTrip(PlanetModel.WGS84, -90 * 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) * DEGREES_TO_RADIANS;
+      final double pLon = (randomFloat() * 360.0 - 180.0) * 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) * DEGREES_TO_RADIANS;
+      final double p1Lon = (randomFloat() * 360.0 - 180.0) * DEGREES_TO_RADIANS;
+      final double p2Lat = (randomFloat() * 180.0 - 90.0) * DEGREES_TO_RADIANS;
+      final double p2Lon = (randomFloat() * 360.0 - 180.0) * 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/3a31a8c7/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
new file mode 100755
index 0000000..d9b220d
--- /dev/null
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
@@ -0,0 +1,165 @@
+/*
+ * 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.spatial3d.geom;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class GeoPolygonTest {
+
+
+  @Test
+  public void testPolygonPointWithin() {
+    GeoMembershipShape c;
+    GeoPoint gp;
+    List<GeoPoint> points;
+
+    points = new ArrayList<GeoPoint>();
+    points.add(new GeoPoint(PlanetModel.SPHERE, -0.1, -0.5));
+    points.add(new GeoPoint(PlanetModel.SPHERE, 0.0, -0.6));
+    points.add(new GeoPoint(PlanetModel.SPHERE, 0.1, -0.5));
+    points.add(new GeoPoint(PlanetModel.SPHERE, 0.0, -0.4));
+
+    c = GeoPolygonFactory.makeGeoPolygon(PlanetModel.SPHERE, points, 0);
+    // Sample some points within
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.55);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.45);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.05, -0.5);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, -0.5);
+    assertTrue(c.isWithin(gp));
+    // Sample some nearby points outside
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.65);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.35);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.15, -0.5);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.15, -0.5);
+    assertFalse(c.isWithin(gp));
+    // Random points outside
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.5, 0.0);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
+    assertFalse(c.isWithin(gp));
+
+    points = new ArrayList<GeoPoint>();
+    points.add(new GeoPoint(PlanetModel.SPHERE, -0.1, -0.5));
+    points.add(new GeoPoint(PlanetModel.SPHERE, -0.01, -0.6));
+    points.add(new GeoPoint(PlanetModel.SPHERE, -0.1, -0.7));
+    points.add(new GeoPoint(PlanetModel.SPHERE, 0.0, -0.8));
+    points.add(new GeoPoint(PlanetModel.SPHERE, 0.1, -0.7));
+    points.add(new GeoPoint(PlanetModel.SPHERE, 0.01, -0.6));
+    points.add(new GeoPoint(PlanetModel.SPHERE, 0.1, -0.5));
+    points.add(new GeoPoint(PlanetModel.SPHERE, 0.0, -0.4));
+        
+        /*
+        System.out.println("Points: ");
+        for (GeoPoint p : points) {
+            System.out.println(" "+p);
+        }
+        */
+
+    c = GeoPolygonFactory.makeGeoPolygon(PlanetModel.SPHERE, points, 0);
+    // Sample some points within
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.55);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.45);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.05, -0.5);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, -0.5);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.7);
+    assertTrue(c.isWithin(gp));
+    // Sample some nearby points outside
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.35);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.15, -0.5);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.15, -0.5);
+    assertFalse(c.isWithin(gp));
+    // Random points outside
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.5, 0.0);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
+    assertFalse(c.isWithin(gp));
+
+  }
+
+  @Test
+  public void testPolygonBounds() {
+    GeoMembershipShape c;
+    LatLonBounds b;
+    List<GeoPoint> points;
+    XYZBounds xyzb;
+    GeoPoint point;
+    GeoArea area;
+    
+    // BKD failure
+    points = new ArrayList<GeoPoint>();
+    points.add(new GeoPoint(PlanetModel.WGS84, -0.36716183577912814, 1.4836349969188696));
+    points.add(new GeoPoint(PlanetModel.WGS84, 0.7846038240742979, -0.02743348424931823));
+    points.add(new GeoPoint(PlanetModel.WGS84, -0.7376479402362607, -0.5072961758807019));
+    points.add(new GeoPoint(PlanetModel.WGS84, -0.3760415907667887, 1.4970455334565513));
+    
+    c = GeoPolygonFactory.makeGeoPolygon(PlanetModel.WGS84, points, 1);
+    
+    point = new GeoPoint(PlanetModel.WGS84, -0.01580760332365284, -0.03956004622490505);
+    assertTrue(c.isWithin(point));
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84,
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    assertTrue(area.isWithin(point));
+    
+    points = new ArrayList<GeoPoint>();
+    points.add(new GeoPoint(PlanetModel.SPHERE, -0.1, -0.5));
+    points.add(new GeoPoint(PlanetModel.SPHERE, 0.0, -0.6));
+    points.add(new GeoPoint(PlanetModel.SPHERE, 0.1, -0.5));
+    points.add(new GeoPoint(PlanetModel.SPHERE, 0.0, -0.4));
+
+    c = GeoPolygonFactory.makeGeoPolygon(PlanetModel.SPHERE, points, 0);
+
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(-0.6, b.getLeftLongitude(), 0.000001);
+    assertEquals(-0.4, b.getRightLongitude(), 0.000001);
+    assertEquals(-0.1, b.getMinLatitude(), 0.000001);
+    assertEquals(0.1, b.getMaxLatitude(), 0.000001);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/PlaneTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/PlaneTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/PlaneTest.java
new file mode 100644
index 0000000..91bd0c3
--- /dev/null
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/PlaneTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.spatial3d.geom;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test basic plane functionality.
+ */
+public class PlaneTest {
+
+
+  @Test
+  public void testIdenticalPlanes() {
+    final GeoPoint p = new GeoPoint(PlanetModel.SPHERE, 0.123, -0.456);
+    final Plane plane1 = new Plane(p, 0.0);
+    final Plane plane2 = new Plane(p, 0.0);
+    assertTrue(plane1.isNumericallyIdentical(plane2));
+    final Plane plane3 = new Plane(p, 0.1);
+    assertFalse(plane1.isNumericallyIdentical(plane3));
+    final Vector v1 = new Vector(0.1, -0.732, 0.9);
+    final double constant = 0.432;
+    final Vector v2 = new Vector(v1.x * constant, v1.y * constant, v1.z * constant);
+    final Plane p1 = new Plane(v1, 0.2);
+    final Plane p2 = new Plane(v2, 0.2 * constant);
+    assertTrue(p1.isNumericallyIdentical(p2));
+  }
+
+  @Test
+  public void testInterpolation() {
+    // [X=0.35168818443386646, Y=-0.19637966197066342, Z=0.9152870857244183],
+    // [X=0.5003343189532654, Y=0.522128543226148, Z=0.6906861469771293],
+
+    final GeoPoint start = new GeoPoint(0.35168818443386646, -0.19637966197066342, 0.9152870857244183);
+    final GeoPoint end = new GeoPoint(0.5003343189532654, 0.522128543226148, 0.6906861469771293);
+
+    // [A=-0.6135342247741855, B=0.21504338363863665, C=0.28188192383666794, D=0.0, side=-1.0] internal? false;
+    final Plane p = new Plane(-0.6135342247741855, 0.21504338363863665, 0.28188192383666794, 0.0);
+
+    final GeoPoint[] points = p.interpolate(start, end, new double[]{0.25, 0.50, 0.75});
+
+    for (GeoPoint point : points) {
+      assertTrue(p.evaluateIsZero(point));
+    }
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/XYZSolidTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/XYZSolidTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/XYZSolidTest.java
new file mode 100644
index 0000000..98c616e
--- /dev/null
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/XYZSolidTest.java
@@ -0,0 +1,220 @@
+/*
+ * 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.spatial3d.geom;
+
+import org.apache.lucene.util.LuceneTestCase;
+import org.junit.Test;
+
+public class XYZSolidTest extends LuceneTestCase {
+
+  @Test
+  public void testNonDegenerateRelationships() {
+    XYZSolid s;
+    GeoShape shape;
+    // Something bigger than the world
+    s = new StandardXYZSolid(PlanetModel.SPHERE, -2.0, 2.0, -2.0, 2.0, -2.0, 2.0);
+    // Any shape, except whole world, should be within.
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.WITHIN, s.getRelationship(shape));
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    // An XYZSolid represents a surface shape, which when larger than the world is in fact
+    // the entire world, so it should overlap the world.
+    assertEquals(GeoArea.OVERLAPS, s.getRelationship(shape));
+
+    // Something overlapping the world on only one side
+    s = new StandardXYZSolid(PlanetModel.SPHERE, -2.0, 0.0, -2.0, 2.0, -2.0, 2.0);
+    // Some things should be disjoint...
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, s.getRelationship(shape));
+    // And, some things should be within... 
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI, 0.1);
+    assertEquals(GeoArea.WITHIN, s.getRelationship(shape));
+    // And, some things should overlap.
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI * 0.5, 0.1);
+    assertEquals(GeoArea.OVERLAPS, s.getRelationship(shape));
+
+    // Partial world should be contained by GeoWorld object...
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.CONTAINS, s.getRelationship(shape));
+    
+    // Something inside the world
+    s = new StandardXYZSolid(PlanetModel.SPHERE, -0.1, 0.1, -0.1, 0.1, -0.1, 0.1);
+    // All shapes should be disjoint
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, s.getRelationship(shape));
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.DISJOINT, s.getRelationship(shape));
+    
+  }
+
+  @Test
+  public void testDegenerateRelationships() {
+    GeoArea solid;
+    GeoShape shape;
+    
+    // Basic test of the factory method - non-degenerate
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, -2.0, 2.0, -2.0, 2.0, -2.0, 2.0);
+    // Any shape, except whole world, should be within.
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.WITHIN, solid.getRelationship(shape));
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    // An XYZSolid represents a surface shape, which when larger than the world is in fact
+    // the entire world, so it should overlap the world.
+    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
+
+    // Build a degenerate point, not on sphere
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+    // disjoint with everything?
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+
+    // Build a degenerate point that IS on the sphere
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0);
+    // inside everything that it touches?
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+
+    // Build a shape degenerate in (x,y), which has no points on sphere
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, 0.0, 0.0, -0.1, 0.1);
+    // disjoint with everything?
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+
+    // Build a shape degenerate in (x,y) which has one point on sphere
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, 0.0, 0.0, -0.1, 1.1);
+    // inside everything that it touches?
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, Math.PI * 0.5, 0.0, 0.1);
+    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+
+    // Build a shape degenerate in (x,y) which has two points on sphere
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, 0.0, 0.0, -1.1, 1.1);
+    // inside everything that it touches?
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, Math.PI * 0.5, 0.0, 0.1);
+    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0, 0.1);
+    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
+    
+    // Build a shape degenerate in (x,z), which has no points on sphere
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, -0.1, 0.1, 0.0, 0.0);
+    // disjoint with everything?
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+
+    // Build a shape degenerate in (x,z) which has one point on sphere
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, -0.1, 1.1, 0.0, 0.0);
+    // inside everything that it touches?
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI * 0.5, 0.1);
+    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, -Math.PI * 0.5, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+
+    // Build a shape degenerate in (x,y) which has two points on sphere
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, -1.1, 1.1, 0.0, 0.0);
+    // inside everything that it touches?
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI * 0.5, 0.1);
+    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, -Math.PI * 0.5, 0.1);
+    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
+
+    // MHL for y-z check
+    
+    // Build a shape that is degenerate in x, which has zero points intersecting sphere
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, -0.1, 0.1, -0.1, 0.1);
+    // disjoint with everything?
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+
+    // Build a shape that is degenerate in x, which has zero points intersecting sphere, second variation
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, -0.1, 0.1, 1.1, 1.2);
+    // disjoint with everything?
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+
+    // Build a shape that is disjoint in X but intersects sphere in a complete circle
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, -1.1, 1.1, -1.1, 1.1);
+    // inside everything that it touches?
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI * 0.5, 0.1);
+    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, -Math.PI * 0.5, 0.1);
+    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, Math.PI * 0.5, 0.0, 0.1);
+    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0, 0.1);
+    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
+
+    // Build a shape that is disjoint in X but intersects sphere in a half circle in Y
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, 0.0, 1.1, -1.1, 1.1);
+    // inside everything that it touches?
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI * 0.5, 0.1);
+    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, -Math.PI * 0.5, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, Math.PI * 0.5, 0.0, 0.1);
+    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0, 0.1);
+    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
+
+    // MHL for degenerate Y
+    // MHL for degenerate Z
+    
+  }
+  
+}


[19/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 3a31a8c)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXYdZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXYdZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXYdZSolid.java
new file mode 100644
index 0000000..d824f26
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXYdZSolid.java
@@ -0,0 +1,138 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in X and Z.
+ * This figure, in fact, represents either zero, one, or two points, so the
+ * actual data stored is minimal.
+ *
+ * @lucene.internal
+ */
+public class dXYdZSolid extends BaseXYZSolid {
+
+  /** The points in this figure on the planet surface; also doubles for edge points */
+  protected final GeoPoint[] surfacePoints;
+  
+  /**
+   * Sole constructor
+   *
+   *@param planetModel is the planet model.
+   *@param X is the X value.
+   *@param minY is the minimum Y value.
+   *@param maxY is the maximum Y value.
+   *@param Z is the Z value.
+   */
+  public dXYdZSolid(final PlanetModel planetModel,
+    final double X,
+    final double minY,
+    final double maxY,
+    final double Z) {
+    super(planetModel);
+    // Argument checking
+    if (maxY - minY < Vector.MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("Y values in wrong order or identical");
+
+    // Build the planes and intersect them.
+    final Plane xPlane = new Plane(xUnitVector,-X);
+    final Plane zPlane = new Plane(zUnitVector,-Z);
+    final SidedPlane minYPlane = new SidedPlane(0.0,maxY,0.0,yUnitVector,-minY);
+    final SidedPlane maxYPlane = new SidedPlane(0.0,minY,0.0,yUnitVector,-maxY);
+    surfacePoints = xPlane.findIntersections(planetModel,zPlane,minYPlane,maxYPlane);
+  }
+
+  @Override
+  protected GeoPoint[] getEdgePoints() {
+    return surfacePoints;
+  }
+  
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    for (final GeoPoint p : surfacePoints) {
+      if (p.isIdentical(x,y,z))
+        return true;
+    }
+    return false;
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    //System.err.println(this+" getrelationship with "+path);
+    final int insideRectangle = isShapeInsideArea(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some inside");
+      return OVERLAPS;
+    }
+
+    // Figure out if the entire XYZArea is contained by the shape.
+    final int insideShape = isAreaInsideShape(path);
+    if (insideShape == SOME_INSIDE) {
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
+      //System.err.println(" inside of each other");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      return WITHIN;
+    }
+    
+    if (insideShape == ALL_INSIDE) {
+      //System.err.println(" shape contains rectangle");
+      return CONTAINS;
+    }
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof dXYdZSolid))
+      return false;
+    dXYdZSolid other = (dXYdZSolid) o;
+    if (!super.equals(other) || surfacePoints.length != other.surfacePoints.length ) {
+      return false;
+    }
+    for (int i = 0; i < surfacePoints.length; i++) {
+      if (!surfacePoints[i].equals(other.surfacePoints[i]))
+        return false;
+    }
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    for (final GeoPoint p : surfacePoints) {
+      result = 31 * result  + p.hashCode();
+    }
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    final StringBuilder sb = new StringBuilder();
+    for (final GeoPoint p : surfacePoints) {
+      sb.append(" ").append(p).append(" ");
+    }
+    return "dXYdZSolid: {planetmodel="+planetModel+", "+sb.toString()+"}";
+  }
+  
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXdYZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXdYZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXdYZSolid.java
new file mode 100644
index 0000000..b9942b5
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXdYZSolid.java
@@ -0,0 +1,138 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in X and Y.
+ * This figure, in fact, represents either zero, one, or two points, so the
+ * actual data stored is minimal.
+ *
+ * @lucene.internal
+ */
+public class dXdYZSolid extends BaseXYZSolid {
+
+  /** The points in this figure on the planet surface; also doubles for edge points */
+  protected final GeoPoint[] surfacePoints;
+  
+  /**
+   * Sole constructor
+   *
+   *@param planetModel is the planet model.
+   *@param X is the X value.
+   *@param Y is the Y value.
+   *@param minZ is the minimum Z value.
+   *@param maxZ is the maximum Z value.
+   */
+  public dXdYZSolid(final PlanetModel planetModel,
+    final double X,
+    final double Y,
+    final double minZ,
+    final double maxZ) {
+    super(planetModel);
+    // Argument checking
+    if (maxZ - minZ < Vector.MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("Z values in wrong order or identical");
+
+    // Build the planes and intersect them.
+    final Plane xPlane = new Plane(xUnitVector,-X);
+    final Plane yPlane = new Plane(yUnitVector,-Y);
+    final SidedPlane minZPlane = new SidedPlane(0.0,0.0,maxZ,zUnitVector,-minZ);
+    final SidedPlane maxZPlane = new SidedPlane(0.0,0.0,minZ,zUnitVector,-maxZ);
+    surfacePoints = xPlane.findIntersections(planetModel,yPlane,minZPlane,maxZPlane);
+  }
+
+  @Override
+  protected GeoPoint[] getEdgePoints() {
+    return surfacePoints;
+  }
+  
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    for (final GeoPoint p : surfacePoints) {
+      if (p.isIdentical(x,y,z))
+        return true;
+    }
+    return false;
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    //System.err.println(this+" getrelationship with "+path);
+    final int insideRectangle = isShapeInsideArea(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some inside");
+      return OVERLAPS;
+    }
+
+    // Figure out if the entire XYZArea is contained by the shape.
+    final int insideShape = isAreaInsideShape(path);
+    if (insideShape == SOME_INSIDE) {
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
+      //System.err.println(" inside of each other");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      return WITHIN;
+    }
+    
+    if (insideShape == ALL_INSIDE) {
+      //System.err.println(" shape contains rectangle");
+      return CONTAINS;
+    }
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof dXdYZSolid))
+      return false;
+    dXdYZSolid other = (dXdYZSolid) o;
+    if (!super.equals(other) || surfacePoints.length != other.surfacePoints.length ) {
+      return false;
+    }
+    for (int i = 0; i < surfacePoints.length; i++) {
+      if (!surfacePoints[i].equals(other.surfacePoints[i]))
+        return false;
+    }
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    for (final GeoPoint p : surfacePoints) {
+      result = 31 * result  + p.hashCode();
+    }
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    final StringBuilder sb = new StringBuilder();
+    for (final GeoPoint p : surfacePoints) {
+      sb.append(" ").append(p).append(" ");
+    }
+    return "dXdYZSolid: {planetmodel="+planetModel+", "+sb.toString()+"}";
+  }
+  
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXdYdZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXdYdZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXdYdZSolid.java
new file mode 100644
index 0000000..66dcab8
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXdYdZSolid.java
@@ -0,0 +1,146 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in all dimensions
+ *
+ * @lucene.internal
+ */
+public class dXdYdZSolid extends BaseXYZSolid {
+
+  /** On surface? */
+  protected final boolean isOnSurface;
+  /** The point */
+  protected final GeoPoint thePoint;
+  
+  /** These are the edge points of the shape, which are defined to be at least one point on
+   * each surface area boundary.  In the case of a solid, this includes points which represent
+   * the intersection of XYZ bounding planes and the planet, as well as points representing
+   * the intersection of single bounding planes with the planet itself.
+   */
+  protected final GeoPoint[] edgePoints;
+
+  /** Empty array of {@link GeoPoint}. */
+  protected static final GeoPoint[] nullPoints = new GeoPoint[0];
+  
+  /**
+   * Sole constructor
+   *
+   *@param planetModel is the planet model.
+   *@param X is the X value.
+   *@param Y is the Y value.
+   *@param Z is the Z value.
+   */
+  public dXdYdZSolid(final PlanetModel planetModel,
+    final double X,
+    final double Y,
+    final double Z) {
+    super(planetModel);
+    isOnSurface = planetModel.pointOnSurface(X,Y,Z);
+    if (isOnSurface) {
+      thePoint = new GeoPoint(X,Y,Z);
+      edgePoints = new GeoPoint[]{thePoint};
+    } else {
+      thePoint = null;
+      edgePoints = nullPoints;
+    }
+  }
+
+  @Override
+  protected GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+  
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    if (!isOnSurface) {
+      return false;
+    }
+    return thePoint.isIdentical(x,y,z);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    if (!isOnSurface) {
+      return DISJOINT;
+    }
+    
+    //System.err.println(this+" getrelationship with "+path);
+    final int insideRectangle = isShapeInsideArea(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some shape points inside area");
+      return OVERLAPS;
+    }
+
+    // Figure out if the entire XYZArea is contained by the shape.
+    final int insideShape = isAreaInsideShape(path);
+    if (insideShape == SOME_INSIDE) {
+      //System.err.println(" some area points inside shape");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
+      //System.err.println(" inside of each other");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      //System.err.println(" shape inside area entirely");
+      return WITHIN;
+    }
+
+    if (insideShape == ALL_INSIDE) {
+      //System.err.println(" shape contains area entirely");
+      return CONTAINS;
+    }
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof dXdYdZSolid))
+      return false;
+    dXdYdZSolid other = (dXdYdZSolid) o;
+    if (!super.equals(other) ||
+      other.isOnSurface != isOnSurface) {
+      return false;
+    }
+    if (isOnSurface) {
+      return other.thePoint.equals(thePoint);
+    }
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + (isOnSurface?1:0);
+    if (isOnSurface) {
+      result = 31 * result  + thePoint.hashCode();
+    }
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "dXdYdZSolid: {planetmodel="+planetModel+", isOnSurface="+isOnSurface+", thePoint="+thePoint+"}";
+  }
+  
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/package-info.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/package-info.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/package-info.java
new file mode 100644
index 0000000..446365c
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/**
+ * Shapes implemented using 3D planar geometry.  This package has no dependencies aside from Java.
+ * This code was contributed under the name "Geo3D".
+ */
+package org.apache.lucene.spatial3d.geom;

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/package-info.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/package-info.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/package-info.java
new file mode 100644
index 0000000..032d26f
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+/**
+ * Lucene field &amp; query support for the spatial geometry implemented in {@link org.apache.lucene.spatial3d.geom}.
+ */
+package org.apache.lucene.spatial3d;

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/overview.html
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/overview.html b/lucene/spatial3d/src/java/overview.html
index 152d06e..293cc65a 100644
--- a/lucene/spatial3d/src/java/overview.html
+++ b/lucene/spatial3d/src/java/overview.html
@@ -23,7 +23,8 @@
   <h1>The Spatial3D Module for Apache Lucene</h1>
 
   <p>
-    APIs for planar spatial3d math.
+    APIs for planar spatial3d math.  It is mostly comprised of computational geometry code in the
+    "org.apache.lucene.spatial3d.geom" package (AKA "Geo3D").
   </p>
   </body>
 </html>

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoBBoxTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoBBoxTest.java b/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoBBoxTest.java
deleted file mode 100755
index b76134e..0000000
--- a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoBBoxTest.java
+++ /dev/null
@@ -1,364 +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.geo3d;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-public class GeoBBoxTest {
-
-  protected final double DEGREES_TO_RADIANS = Math.PI / 180.0;
-
-  @Test
-  public void testBBoxDegenerate() {
-    GeoBBox box;
-    GeoConvexPolygon cp;
-    int relationship;
-    List<GeoPoint> points = new ArrayList<GeoPoint>();
-    points.add(new GeoPoint(PlanetModel.SPHERE, 24 * DEGREES_TO_RADIANS, -30 * DEGREES_TO_RADIANS));
-    points.add(new GeoPoint(PlanetModel.SPHERE, -11 * DEGREES_TO_RADIANS, 101 * DEGREES_TO_RADIANS));
-    points.add(new GeoPoint(PlanetModel.SPHERE, -49 * DEGREES_TO_RADIANS, -176 * DEGREES_TO_RADIANS));
-    GeoMembershipShape shape = GeoPolygonFactory.makeGeoPolygon(PlanetModel.SPHERE, points, 0);
-    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, -64 * DEGREES_TO_RADIANS, -64 * DEGREES_TO_RADIANS, -180 * DEGREES_TO_RADIANS, 180 * DEGREES_TO_RADIANS);
-    relationship = box.getRelationship(shape);
-    assertEquals(GeoArea.CONTAINS, relationship);
-    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, -61.85 * DEGREES_TO_RADIANS, -67.5 * DEGREES_TO_RADIANS, -180 * DEGREES_TO_RADIANS, -168.75 * DEGREES_TO_RADIANS);
-    //System.out.println("Shape = " + shape + " Rect = " + box);
-    relationship = box.getRelationship(shape);
-    assertEquals(GeoArea.CONTAINS, relationship);
-  }
-
-  @Test
-  public void testBBoxPointWithin() {
-    GeoBBox box;
-    GeoPoint gp;
-
-    // Standard normal Rect box, not crossing dateline
-    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, -1.0, 1.0);
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, 0.0);
-    assertTrue(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.1, 0.0);
-    assertFalse(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0);
-    assertFalse(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, 1.1);
-    assertFalse(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -1.1);
-    assertFalse(box.isWithin(gp));
-    assertEquals(0.1,box.computeOutsideDistance(DistanceStyle.ARC,gp),1e-2);
-    assertEquals(0.1,box.computeOutsideDistance(DistanceStyle.NORMAL,gp),1e-2);
-    assertEquals(0.1,box.computeOutsideDistance(DistanceStyle.NORMAL,gp),1e-2);
-
-    // Standard normal Rect box, crossing dateline
-    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, Math.PI - 1.0, -Math.PI + 1.0);
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -Math.PI);
-    assertTrue(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.1, -Math.PI);
-    assertFalse(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.5, -Math.PI);
-    assertFalse(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -Math.PI + 1.1);
-    assertFalse(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, (-Math.PI - 1.1) + Math.PI * 2.0);
-    assertFalse(box.isWithin(gp));
-
-    // Latitude zone rectangle
-    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, -Math.PI, Math.PI);
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -Math.PI);
-    assertTrue(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.1, -Math.PI);
-    assertFalse(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.5, -Math.PI);
-    assertFalse(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -Math.PI + 1.1);
-    assertTrue(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, (-Math.PI - 1.1) + Math.PI * 2.0);
-    assertTrue(box.isWithin(gp));
-
-    // World
-    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, -Math.PI, Math.PI);
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -Math.PI);
-    assertTrue(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.1, -Math.PI);
-    assertTrue(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.5, -Math.PI);
-    assertTrue(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -Math.PI + 1.1);
-    assertTrue(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, (-Math.PI - 1.1) + Math.PI * 2.0);
-    assertTrue(box.isWithin(gp));
-
-  }
-
-  @Test
-  public void testBBoxExpand() {
-    GeoBBox box;
-    GeoPoint gp;
-    // Standard normal Rect box, not crossing dateline
-    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, -1.0, 1.0);
-    box = box.expand(0.1);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, 0.0);
-    assertTrue(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.15, 0.0);
-    assertFalse(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.25 - 0.05, 0.0);
-    assertTrue(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.25 - 0.15, 0.0);
-    assertFalse(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -1.05);
-    assertTrue(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -1.15);
-    assertFalse(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, 1.05);
-    assertTrue(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, 1.15);
-    assertFalse(box.isWithin(gp));
-  }
-
-  @Test
-  public void testBBoxBounds() {
-    GeoBBox c;
-    LatLonBounds b;
-    XYZBounds xyzb;
-    GeoArea solid;
-    GeoPoint point;
-    int relationship;
-    
-    c= GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.7570958596622309, -0.7458670829264561, -0.9566079379002148, 1.4802570961901191);
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE,0.10922258701604912,0.1248184603754517,-0.8172414690802067,0.9959041483215542,-0.6136586624726926,0.6821740363641521);
-    point = new GeoPoint(PlanetModel.SPHERE, 0.3719987557178081, 1.4529582778845198);
-    assertTrue(c.isWithin(point));
-    assertTrue(solid.isWithin(point));
-    relationship = solid.getRelationship(c);
-    assertTrue(relationship == GeoArea.OVERLAPS || relationship == GeoArea.CONTAINS || relationship == GeoArea.WITHIN);
-
-    c= GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.006607096847842122, -0.002828135860810422, -0.0012934461873348349, 0.006727418645092394);
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE,0.9999995988328008,1.0000000002328306,-0.0012934708508166816,0.006727393021214471,-0.002828157275369464,0.006607074060760007);
-    point = new GeoPoint(PlanetModel.SPHERE, -5.236470872437899E-4, 3.992578692654256E-4);
-    assertTrue(c.isWithin(point));
-    assertTrue(solid.isWithin(point));
-    relationship = solid.getRelationship(c);
-    assertTrue(relationship == GeoArea.OVERLAPS || relationship == GeoArea.CONTAINS || relationship == GeoArea.WITHIN);
-    
-    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.25, -Math.PI * 0.25, -1.0, 1.0);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(-1.0, b.getLeftLongitude(), 0.000001);
-    assertEquals(1.0, b.getRightLongitude(), 0.000001);
-    assertEquals(-Math.PI * 0.25, b.getMinLatitude(), 0.000001);
-    assertEquals(Math.PI * 0.25, b.getMaxLatitude(), 0.000001);
-    assertEquals(0.382051, xyzb.getMinimumX(), 0.000001);
-    assertEquals(1.0, xyzb.getMaximumX(), 0.000001);
-    assertEquals(-0.841471, xyzb.getMinimumY(), 0.000001);
-    assertEquals(0.841471, xyzb.getMaximumY(), 0.000001);
-    assertEquals(-0.707107, xyzb.getMinimumZ(), 0.000001);
-    assertEquals(0.707107, xyzb.getMaximumZ(), 0.000001);
-    
-    GeoArea area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE,
-      xyzb.getMinimumX() - 2.0 * Vector.MINIMUM_RESOLUTION,
-      xyzb.getMaximumX() + 2.0 * Vector.MINIMUM_RESOLUTION,
-      xyzb.getMinimumY() - 2.0 * Vector.MINIMUM_RESOLUTION,
-      xyzb.getMaximumY() + 2.0 * Vector.MINIMUM_RESOLUTION,
-      xyzb.getMinimumZ() - 2.0 * Vector.MINIMUM_RESOLUTION,
-      xyzb.getMaximumZ() + 2.0 * Vector.MINIMUM_RESOLUTION);
-    assertEquals(GeoArea.WITHIN, area.getRelationship(c));
-
-    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, -1.0, 1.0);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(-1.0, b.getLeftLongitude(), 0.000001);
-    assertEquals(1.0, b.getRightLongitude(), 0.000001);
-    assertEquals(-Math.PI * 0.25, b.getMinLatitude(), 0.000001);
-    assertEquals(0.0, b.getMaxLatitude(), 0.000001);
-    assertEquals(0.382051, xyzb.getMinimumX(), 0.000001);
-    assertEquals(1.0, xyzb.getMaximumX(), 0.000001);
-    assertEquals(-0.841471, xyzb.getMinimumY(), 0.000001);
-    assertEquals(0.841471, xyzb.getMaximumY(), 0.000001);
-    assertEquals(-0.707107, xyzb.getMinimumZ(), 0.000001);
-    assertEquals(0.0, xyzb.getMaximumZ(), 0.000001);
-
-    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, 1.0, -1.0);
-
-    b = new LatLonBounds();
-    c.getBounds(b);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    assertTrue(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    //assertEquals(1.0,b.getLeftLongitude(),0.000001);
-    //assertEquals(-1.0,b.getRightLongitude(),0.000001);
-    assertEquals(-Math.PI * 0.25, b.getMinLatitude(), 0.000001);
-    assertEquals(0.0, b.getMaxLatitude(), 0.000001);
-    assertEquals(-1.0, xyzb.getMinimumX(), 0.000001);
-    assertEquals(0.540303, xyzb.getMaximumX(), 0.000001);
-    assertEquals(-1.0, xyzb.getMinimumY(), 0.000001);
-    assertEquals(1.0, xyzb.getMaximumY(), 0.000001);
-    assertEquals(-0.707107, xyzb.getMinimumZ(), 0.000001);
-    assertEquals(0.0, xyzb.getMaximumZ(), 0.000001);
-
-
-    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, -1.0, 1.0);
-
-    b = new LatLonBounds();
-    c.getBounds(b);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    assertTrue(b.checkNoLongitudeBound());
-    assertTrue(b.checkNoTopLatitudeBound());
-    assertTrue(b.checkNoBottomLatitudeBound());
-    //assertEquals(-1.0, b.getLeftLongitude(), 0.000001);
-    //assertEquals(1.0, b.getRightLongitude(), 0.000001);
-    assertEquals(0.0, xyzb.getMinimumX(), 0.000001);
-    assertEquals(1.0, xyzb.getMaximumX(), 0.000001);
-    assertEquals(-0.841471, xyzb.getMinimumY(), 0.000001);
-    assertEquals(0.841471, xyzb.getMaximumY(), 0.000001);
-    assertEquals(-1.0, xyzb.getMinimumZ(), 0.000001);
-    assertEquals(1.0, xyzb.getMaximumZ(), 0.000001);
-
-    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, 1.0, -1.0);
-
-    b = new LatLonBounds();
-    c.getBounds(b);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    assertTrue(b.checkNoLongitudeBound());
-    assertTrue(b.checkNoTopLatitudeBound());
-    assertTrue(b.checkNoBottomLatitudeBound());
-    //assertEquals(1.0,b.getLeftLongitude(),0.000001);
-    //assertEquals(-1.0,b.getRightLongitude(),0.000001);
-    assertEquals(-1.0, xyzb.getMinimumX(), 0.000001);
-    assertEquals(0.540303, xyzb.getMaximumX(), 0.000001);
-    assertEquals(-1.0, xyzb.getMinimumY(), 0.000001);
-    assertEquals(1.0, xyzb.getMaximumY(), 0.000001);
-    assertEquals(-1.0, xyzb.getMinimumZ(), 0.000001);
-    assertEquals(1.0, xyzb.getMaximumZ(), 0.000001);
-
-    // Check wide variants of rectangle and longitude slice
-
-    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, -Math.PI + 0.1, Math.PI - 0.1);
-
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertTrue(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    //assertEquals(-Math.PI+0.1,b.getLeftLongitude(),0.000001);
-    //assertEquals(Math.PI-0.1,b.getRightLongitude(),0.000001);
-    assertEquals(-Math.PI * 0.25, b.getMinLatitude(), 0.000001);
-    assertEquals(0.0, b.getMaxLatitude(), 0.000001);
-
-    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, Math.PI - 0.1, -Math.PI + 0.1);
-
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(Math.PI - 0.1, b.getLeftLongitude(), 0.000001);
-    assertEquals(-Math.PI + 0.1, b.getRightLongitude(), 0.000001);
-    assertEquals(-Math.PI * 0.25, b.getMinLatitude(), 0.000001);
-    assertEquals(0.0, b.getMaxLatitude(), 0.000001);
-
-    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, -Math.PI + 0.1, Math.PI - 0.1);
-
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertTrue(b.checkNoLongitudeBound());
-    assertTrue(b.checkNoTopLatitudeBound());
-    assertTrue(b.checkNoBottomLatitudeBound());
-    //assertEquals(-Math.PI+0.1,b.getLeftLongitude(),0.000001);
-    //assertEquals(Math.PI-0.1,b.getRightLongitude(),0.000001);
-
-    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, Math.PI - 0.1, -Math.PI + 0.1);
-
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertTrue(b.checkNoLongitudeBound());
-    assertTrue(b.checkNoTopLatitudeBound());
-    assertTrue(b.checkNoBottomLatitudeBound());
-    //assertEquals(Math.PI - 0.1, b.getLeftLongitude(), 0.000001);
-    //assertEquals(-Math.PI + 0.1, b.getRightLongitude(), 0.000001);
-
-    // Check latitude zone
-    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 1.0, -1.0, -Math.PI, Math.PI);
-
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertTrue(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(-1.0, b.getMinLatitude(), 0.000001);
-    assertEquals(1.0, b.getMaxLatitude(), 0.000001);
-
-    // Now, combine a few things to test the bounds object
-    GeoBBox c1;
-    GeoBBox c2;
-
-    c1 = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, -Math.PI, 0.0);
-    c2 = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, 0.0, Math.PI);
-
-    b = new LatLonBounds();
-    c1.getBounds(b);
-    c2.getBounds(b);
-    assertTrue(b.checkNoLongitudeBound());
-    assertTrue(b.checkNoTopLatitudeBound());
-    assertTrue(b.checkNoBottomLatitudeBound());
-
-    c1 = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, -Math.PI, 0.0);
-    c2 = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, 0.0, Math.PI * 0.5);
-
-    b = new LatLonBounds();
-    c1.getBounds(b);
-    c2.getBounds(b);
-    assertTrue(b.checkNoLongitudeBound());
-    assertTrue(b.checkNoTopLatitudeBound());
-    assertTrue(b.checkNoBottomLatitudeBound());
-    //assertEquals(-Math.PI,b.getLeftLongitude(),0.000001);
-    //assertEquals(Math.PI*0.5,b.getRightLongitude(),0.000001);
-
-    c1 = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, -Math.PI * 0.5, 0.0);
-    c2 = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, 0.0, Math.PI);
-
-    b = new LatLonBounds();
-    c1.getBounds(b);
-    c2.getBounds(b);
-    assertTrue(b.checkNoLongitudeBound());
-    assertTrue(b.checkNoTopLatitudeBound());
-    assertTrue(b.checkNoBottomLatitudeBound());
-    //assertEquals(-Math.PI * 0.5,b.getLeftLongitude(),0.000001);
-    //assertEquals(Math.PI,b.getRightLongitude(),0.000001);
-
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoCircleTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoCircleTest.java b/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoCircleTest.java
deleted file mode 100755
index aa5c2e3..0000000
--- a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoCircleTest.java
+++ /dev/null
@@ -1,415 +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.geo3d;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import org.apache.lucene.util.LuceneTestCase;
-
-public class GeoCircleTest extends LuceneTestCase {
-
-  @Test
-  public void testCircleDistance() {
-    GeoCircle c;
-    GeoPoint gp;
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, -0.5, 0.1);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
-    assertEquals(Double.MAX_VALUE, c.computeDistance(DistanceStyle.ARC,gp), 0.0);
-    assertEquals(Double.MAX_VALUE, c.computeDistance(DistanceStyle.NORMAL,gp), 0.0);
-    assertEquals(Double.MAX_VALUE, c.computeDistance(DistanceStyle.NORMAL,gp), 0.0);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
-    assertEquals(0.0, c.computeDistance(DistanceStyle.ARC,gp), 0.000001);
-    assertEquals(0.0, c.computeDistance(DistanceStyle.NORMAL,gp), 0.000001);
-    assertEquals(0.0, c.computeDistance(DistanceStyle.NORMAL,gp), 0.000001);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, -0.5);
-    assertEquals(0.05, c.computeDistance(DistanceStyle.ARC,gp), 0.000001);
-    assertEquals(0.049995, c.computeDistance(DistanceStyle.LINEAR,gp), 0.000001);
-    assertEquals(0.049979, c.computeDistance(DistanceStyle.NORMAL,gp), 0.000001);
-  }
-
-  @Test
-  public void testCircleFullWorld() {
-    GeoCircle c;
-    GeoPoint gp;
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, -0.5, Math.PI);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.55);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.45);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.5, 0.0);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
-    assertTrue(c.isWithin(gp));
-    LatLonBounds b = new LatLonBounds();
-    c.getBounds(b);
-    assertTrue(b.checkNoLongitudeBound());
-    assertTrue(b.checkNoTopLatitudeBound());
-    assertTrue(b.checkNoBottomLatitudeBound());
-  }
-
-  @Test
-  public void testCirclePointWithin() {
-    GeoCircle c;
-    GeoPoint gp;
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, -0.5, 0.1);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
-    assertFalse(c.isWithin(gp));
-    assertEquals(0.4,c.computeOutsideDistance(DistanceStyle.ARC,gp),1e-12);
-    assertEquals(0.12,c.computeOutsideDistance(DistanceStyle.NORMAL,gp),0.01);
-    assertEquals(0.4,c.computeOutsideDistance(DistanceStyle.LINEAR,gp),0.01);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.55);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.45);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.5, 0.0);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
-    assertFalse(c.isWithin(gp));
-  }
-
-  @Test
-  public void testCircleBounds() {
-    GeoCircle c;
-    LatLonBounds b;
-    XYZBounds xyzb;
-    GeoArea area;
-    GeoPoint p1;
-    GeoPoint p2;
-    int relationship;
-
-    // ...
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84, -0.005931145568901605, -0.001942031539653079, 1.2991918568260272E-4);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84, 1.001098377143621, 1.001100011578687, -0.00207467080358696, -0.0018136665346280983, -0.006067808248760161, -0.005807683665759485);
-    p1 = new GeoPoint(PlanetModel.WGS84, -0.00591253844632244, -0.0020069187259065093);
-    p2 = new GeoPoint(1.001099185736782, -0.0020091272069679327, -0.005919118245803968);
-    assertTrue(c.isWithin(p1));
-    assertTrue(area.isWithin(p1));
-    relationship = area.getRelationship(c);
-    assertTrue(relationship != GeoArea.DISJOINT);
-
-    // Twelfth BKD discovered failure
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84,-0.00824379317765984,-0.0011677469001838581,0.0011530035396910402);
-    p1 = new GeoPoint(PlanetModel.WGS84,-0.006505092992723671,0.007654282718327381);
-    p2 = new GeoPoint(1.0010681673665647,0.007662608264336381,-0.006512324005914593);
-    assertTrue(!c.isWithin(p1));
-    assertTrue(!c.isWithin(p2));
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84, 
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    relationship = area.getRelationship(c);
-    assertTrue(relationship == GeoArea.OVERLAPS || relationship == GeoArea.WITHIN);
-    // Point is actually outside the bounds, and outside the shape
-    assertTrue(!area.isWithin(p1));
-    // Approximate point the same
-    assertTrue(!area.isWithin(p2));
-    
-    // Eleventh BKD discovered failure
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE,-0.004431288600558495,-0.003687846671278374,1.704543429364245E-8);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    //System.err.println(area);
-    relationship = area.getRelationship(c);
-    assertTrue(GeoArea.WITHIN == relationship || GeoArea.OVERLAPS == relationship);
-
-    // Tenth BKD discovered failure
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84,-0.0018829770647349636,-0.001969499061382591,1.3045439293158305E-5);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84, 
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    //System.err.println(area);
-    relationship = area.getRelationship(c);
-    assertTrue(GeoArea.WITHIN == relationship || GeoArea.OVERLAPS == relationship);
-
-    // Ninth BKD discovered failure
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE,-4.211990380885122E-5,-0.0022958453508173044,1.4318475623498535E-5);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    //System.err.println(area);
-    relationship = area.getRelationship(c);
-    assertTrue(GeoArea.WITHIN == relationship || GeoArea.OVERLAPS == relationship);
-    
-    // Eighth BKD discovered failure
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE,0.005321278689117842,-0.00216937368755372,1.5306034422500785E-4);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    //System.err.println(area);
-    relationship = area.getRelationship(c);
-    assertTrue(GeoArea.WITHIN == relationship || GeoArea.OVERLAPS == relationship);
-
-    // Seventh BKD discovered failure
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE,-0.0021627146783861745, -0.0017298167021592304,2.0818312293195752E-4);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    //System.err.println(area);
-    relationship = area.getRelationship(c);
-    assertTrue(GeoArea.WITHIN == relationship || GeoArea.OVERLAPS == relationship);
-
-    // Sixth BKD discovered failure
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84,-0.006450320645814321,0.004660694205115142,0.00489710732634323);
-    //xyzb = new XYZBounds();
-    //c.getBounds(xyzb);
-    //System.err.println("xmin="+xyzb.getMinimumX()+", xmax="+xyzb.getMaximumX()+",ymin="+xyzb.getMinimumY()+", ymax="+xyzb.getMaximumY()+",zmin="+xyzb.getMinimumZ()+", zmax="+xyzb.getMaximumZ());
-    //xmin=1.0010356621420726, xmax=1.0011141249179447,ymin=-2.5326643901354566E-4, ymax=0.009584741915757169,zmin=-0.011359874956269283, zmax=-0.0015549504447452225
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84,1.0010822580620098,1.0010945779732867,0.007079167343247293,0.007541006774427837,-0.0021855011220022575,-0.001896122718181518);
-    assertTrue(GeoArea.CONTAINS != area.getRelationship(c));
-    /*
-    p1 = new GeoPoint(1.0010893045436076,0.007380935180644008,-0.002140671370616495);
-    // This has a different bounding box, so we can't use it.
-    //p2 = new GeoPoint(PlanetModel.WGS84,-0.002164069780096702, 0.007505617500830066);
-    p2 = new GeoPoint(PlanetModel.WGS84,p1.getLatitude(),p1.getLongitude());
-    assertTrue(PlanetModel.WGS84.pointOnSurface(p2));
-    assertTrue(!c.isWithin(p2));
-    assertTrue(!area.isWithin(p2));
-    assertTrue(!c.isWithin(p1));
-    assertTrue(PlanetModel.WGS84.pointOnSurface(p1)); // This fails
-    assertTrue(!area.isWithin(p1)); // This fails
-    */
-    
-    // Fifth BKD discovered failure
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -0.004282454525970269, -1.6739831367422277E-4, 1.959639723134033E-6);
-    assertTrue(c.isWithin(c.getEdgePoints()[0]));
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE,
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    assertTrue(GeoArea.WITHIN == area.getRelationship(c) || GeoArea.OVERLAPS == area.getRelationship(c));
-    
-    // Fourth BKD discovered failure
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -0.0048795517261255, 0.004053904306995974, 5.93699764258874E-6);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE,
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    assertTrue(GeoArea.WITHIN == area.getRelationship(c) || GeoArea.OVERLAPS == area.getRelationship(c));
-    
-    // Yet another test case from BKD
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84, 0.006229478708446979, 0.005570196723795424, 3.840276763694387E-5);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84,
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    p1 = new GeoPoint(PlanetModel.WGS84, 0.006224927111830945, 0.005597367237251763);
-    p2 = new GeoPoint(1.0010836083810235, 0.005603490759433942, 0.006231850560862502);
-    assertTrue(PlanetModel.WGS84.pointOnSurface(p1));
-    //assertTrue(PlanetModel.WGS84.pointOnSurface(p2));
-    assertTrue(c.isWithin(p1));
-    assertTrue(c.isWithin(p2));
-    assertTrue(area.isWithin(p1));
-    assertTrue(area.isWithin(p2));
-    
-    // Another test case from BKD
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -0.005955031040627789, -0.0029274772647399153, 1.601488279374338E-5);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE,
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    
-    relationship = area.getRelationship(c);
-    assertTrue(relationship == GeoArea.WITHIN || relationship == GeoArea.OVERLAPS);
-    
-    // Test case from BKD
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -0.765816119338, 0.991848766844, 0.8153163226330487);
-    p1 = new GeoPoint(0.7692262265236023, -0.055089298115534646, -0.6365973465711254);
-    assertTrue(c.isWithin(p1));
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    assertTrue(p1.x >= xyzb.getMinimumX() && p1.x <= xyzb.getMaximumX());
-    assertTrue(p1.y >= xyzb.getMinimumY() && p1.y <= xyzb.getMaximumY());
-    assertTrue(p1.z >= xyzb.getMinimumZ() && p1.z <= xyzb.getMaximumZ());
-    
-    // Vertical circle cases
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, -0.5, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(-0.6, b.getLeftLongitude(), 0.000001);
-    assertEquals(-0.4, b.getRightLongitude(), 0.000001);
-    assertEquals(-0.1, b.getMinLatitude(), 0.000001);
-    assertEquals(0.1, b.getMaxLatitude(), 0.000001);
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, 0.5, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(0.4, b.getLeftLongitude(), 0.000001);
-    assertEquals(0.6, b.getRightLongitude(), 0.000001);
-    assertEquals(-0.1, b.getMinLatitude(), 0.000001);
-    assertEquals(0.1, b.getMaxLatitude(), 0.000001);
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(-0.1, b.getLeftLongitude(), 0.000001);
-    assertEquals(0.1, b.getRightLongitude(), 0.000001);
-    assertEquals(-0.1, b.getMinLatitude(), 0.000001);
-    assertEquals(0.1, b.getMaxLatitude(), 0.000001);
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, Math.PI, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(Math.PI - 0.1, b.getLeftLongitude(), 0.000001);
-    assertEquals(-Math.PI + 0.1, b.getRightLongitude(), 0.000001);
-    assertEquals(-0.1, b.getMinLatitude(), 0.000001);
-    assertEquals(0.1, b.getMaxLatitude(), 0.000001);
-    // Horizontal circle cases
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, Math.PI * 0.5, 0.0, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertTrue(b.checkNoLongitudeBound());
-    assertTrue(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(Math.PI * 0.5 - 0.1, b.getMinLatitude(), 0.000001);
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertTrue(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertTrue(b.checkNoBottomLatitudeBound());
-    assertEquals(-Math.PI * 0.5 + 0.1, b.getMaxLatitude(), 0.000001);
-
-    // Now do a somewhat tilted plane, facing different directions.
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, 0.0, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
-    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
-    assertEquals(-0.1, b.getLeftLongitude(), 0.00001);
-    assertEquals(0.1, b.getRightLongitude(), 0.00001);
-
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, Math.PI, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
-    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
-    assertEquals(Math.PI - 0.1, b.getLeftLongitude(), 0.00001);
-    assertEquals(-Math.PI + 0.1, b.getRightLongitude(), 0.00001);
-
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, Math.PI * 0.5, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
-    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
-    assertEquals(Math.PI * 0.5 - 0.1, b.getLeftLongitude(), 0.00001);
-    assertEquals(Math.PI * 0.5 + 0.1, b.getRightLongitude(), 0.00001);
-
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, -Math.PI * 0.5, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
-    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
-    assertEquals(-Math.PI * 0.5 - 0.1, b.getLeftLongitude(), 0.00001);
-    assertEquals(-Math.PI * 0.5 + 0.1, b.getRightLongitude(), 0.00001);
-
-    // Slightly tilted, PI/4 direction.
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, Math.PI * 0.25, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
-    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
-    assertEquals(Math.PI * 0.25 - 0.1, b.getLeftLongitude(), 0.00001);
-    assertEquals(Math.PI * 0.25 + 0.1, b.getRightLongitude(), 0.00001);
-
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, -Math.PI * 0.25, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
-    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
-    assertEquals(-Math.PI * 0.25 - 0.1, b.getLeftLongitude(), 0.00001);
-    assertEquals(-Math.PI * 0.25 + 0.1, b.getRightLongitude(), 0.00001);
-
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -0.01, Math.PI * 0.25, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(0.09, b.getMaxLatitude(), 0.000001);
-    assertEquals(-0.11, b.getMinLatitude(), 0.000001);
-    assertEquals(Math.PI * 0.25 - 0.1, b.getLeftLongitude(), 0.00001);
-    assertEquals(Math.PI * 0.25 + 0.1, b.getRightLongitude(), 0.00001);
-
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -0.01, -Math.PI * 0.25, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(0.09, b.getMaxLatitude(), 0.000001);
-    assertEquals(-0.11, b.getMinLatitude(), 0.000001);
-    assertEquals(-Math.PI * 0.25 - 0.1, b.getLeftLongitude(), 0.00001);
-    assertEquals(-Math.PI * 0.25 + 0.1, b.getRightLongitude(), 0.00001);
-
-    // Now do a somewhat tilted plane.
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, -0.5, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
-    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
-    assertEquals(-0.6, b.getLeftLongitude(), 0.00001);
-    assertEquals(-0.4, b.getRightLongitude(), 0.00001);
-
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoConvexPolygonTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoConvexPolygonTest.java b/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoConvexPolygonTest.java
deleted file mode 100755
index d6ca7ba..0000000
--- a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoConvexPolygonTest.java
+++ /dev/null
@@ -1,91 +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.geo3d;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-public class GeoConvexPolygonTest {
-
-
-  @Test
-  public void testPolygonPointWithin() {
-    GeoConvexPolygon c;
-    GeoPoint gp;
-    c = new GeoConvexPolygon(PlanetModel.SPHERE, -0.1, -0.5);
-    c.addPoint(0.0, -0.6, false);
-    c.addPoint(0.1, -0.5, false);
-    c.addPoint(0.0, -0.4, false);
-    c.done(false);
-    // Sample some points within
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.55);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.45);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.05, -0.5);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, -0.5);
-    assertTrue(c.isWithin(gp));
-    // Sample some nearby points outside, and compute distance-to-shape for them as well
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.65);
-    assertFalse(c.isWithin(gp));
-    assertEquals(0.05,c.computeOutsideDistance(DistanceStyle.ARC,gp),1e-12);
-    assertEquals(0.05,c.computeOutsideDistance(DistanceStyle.NORMAL,gp),1e-3);
-    assertEquals(0.05,c.computeOutsideDistance(DistanceStyle.LINEAR,gp),1e-3);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.35);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.15, -0.5);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.15, -0.5);
-    assertFalse(c.isWithin(gp));
-    // Random points outside
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.5, 0.0);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
-    assertFalse(c.isWithin(gp));
-  }
-
-  @Test
-  public void testPolygonBounds() {
-    GeoConvexPolygon c;
-    LatLonBounds b;
-
-    c = new GeoConvexPolygon(PlanetModel.SPHERE, -0.1, -0.5);
-    c.addPoint(0.0, -0.6, false);
-    c.addPoint(0.1, -0.5, false);
-    c.addPoint(0.0, -0.4, false);
-    c.done(false);
-
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(-0.6, b.getLeftLongitude(), 0.000001);
-    assertEquals(-0.4, b.getRightLongitude(), 0.000001);
-    assertEquals(-0.1, b.getMinLatitude(), 0.000001);
-    assertEquals(0.1, b.getMaxLatitude(), 0.000001);
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoModelTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoModelTest.java b/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoModelTest.java
deleted file mode 100644
index b3001d4..0000000
--- a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoModelTest.java
+++ /dev/null
@@ -1,110 +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.geo3d;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-/**
- * Test basic plane functionality.
- */
-public class GeoModelTest {
-
-  protected final static PlanetModel scaledModel = new PlanetModel(1.2,1.5);
-  
-  @Test
-  public void testBasicCircle() {
-    // The point of this test is just to make sure nothing blows up doing normal things with a quite non-spherical model
-    // Make sure that the north pole is in the circle, and south pole isn't
-    final GeoPoint northPole = new GeoPoint(scaledModel, Math.PI * 0.5, 0.0);
-    final GeoPoint southPole = new GeoPoint(scaledModel, -Math.PI * 0.5, 0.0);
-    final GeoPoint point1 = new GeoPoint(scaledModel, Math.PI * 0.25, 0.0);
-    final GeoPoint point2 = new GeoPoint(scaledModel, Math.PI * 0.125, 0.0);
-    
-    GeoCircle circle = new GeoStandardCircle(scaledModel, Math.PI * 0.5, 0.0, 0.01);
-    assertTrue(circle.isWithin(northPole));
-    assertFalse(circle.isWithin(southPole));
-    assertFalse(circle.isWithin(point1));
-    LatLonBounds bounds;
-    bounds = new LatLonBounds();
-    circle.getBounds(bounds);
-    assertTrue(bounds.checkNoLongitudeBound());
-    assertTrue(bounds.checkNoTopLatitudeBound());
-    assertFalse(bounds.checkNoBottomLatitudeBound());
-    assertEquals(Math.PI * 0.5 - 0.01, bounds.getMinLatitude(), 0.01);
-
-    circle = new GeoStandardCircle(scaledModel, Math.PI * 0.25, 0.0, 0.01);
-    assertTrue(circle.isWithin(point1));
-    assertFalse(circle.isWithin(northPole));
-    assertFalse(circle.isWithin(southPole));
-    bounds = new LatLonBounds();
-    circle.getBounds(bounds);
-    assertFalse(bounds.checkNoTopLatitudeBound());
-    assertFalse(bounds.checkNoLongitudeBound());
-    assertFalse(bounds.checkNoBottomLatitudeBound());
-    assertEquals(Math.PI * 0.25 + 0.01, bounds.getMaxLatitude(), 0.00001);
-    assertEquals(Math.PI * 0.25 - 0.01, bounds.getMinLatitude(), 0.00001);
-    assertEquals(-0.0125, bounds.getLeftLongitude(), 0.0001);
-    assertEquals(0.0125, bounds.getRightLongitude(), 0.0001);
-
-    circle = new GeoStandardCircle(scaledModel, Math.PI * 0.125, 0.0, 0.01);
-    assertTrue(circle.isWithin(point2));
-    assertFalse(circle.isWithin(northPole));
-    assertFalse(circle.isWithin(southPole));
-    bounds = new LatLonBounds();
-    circle.getBounds(bounds);
-    assertFalse(bounds.checkNoLongitudeBound());
-    assertFalse(bounds.checkNoTopLatitudeBound());
-    assertFalse(bounds.checkNoBottomLatitudeBound());
-    // Symmetric, as expected
-    assertEquals(Math.PI * 0.125 - 0.01, bounds.getMinLatitude(), 0.00001);
-    assertEquals(Math.PI * 0.125 + 0.01, bounds.getMaxLatitude(), 0.00001);
-    assertEquals(-0.0089, bounds.getLeftLongitude(), 0.0001);
-    assertEquals(0.0089, bounds.getRightLongitude(), 0.0001);
-
-  }
-
-  @Test
-  public void testBasicRectangle() {
-    final GeoBBox bbox = GeoBBoxFactory.makeGeoBBox(scaledModel, 1.0, 0.0, 0.0, 1.0);
-    final GeoPoint insidePoint = new GeoPoint(scaledModel, 0.5, 0.5);
-    assertTrue(bbox.isWithin(insidePoint));
-    final GeoPoint topOutsidePoint = new GeoPoint(scaledModel, 1.01, 0.5);
-    assertFalse(bbox.isWithin(topOutsidePoint));
-    final GeoPoint bottomOutsidePoint = new GeoPoint(scaledModel, -0.01, 0.5);
-    assertFalse(bbox.isWithin(bottomOutsidePoint));
-    final GeoPoint leftOutsidePoint = new GeoPoint(scaledModel, 0.5, -0.01);
-    assertFalse(bbox.isWithin(leftOutsidePoint));
-    final GeoPoint rightOutsidePoint = new GeoPoint(scaledModel, 0.5, 1.01);
-    assertFalse(bbox.isWithin(rightOutsidePoint));
-    final LatLonBounds bounds = new LatLonBounds();
-    bbox.getBounds(bounds);
-    assertFalse(bounds.checkNoLongitudeBound());
-    assertFalse(bounds.checkNoTopLatitudeBound());
-    assertFalse(bounds.checkNoBottomLatitudeBound());
-    assertEquals(1.0, bounds.getMaxLatitude(), 0.00001);
-    assertEquals(0.0, bounds.getMinLatitude(), 0.00001);
-    assertEquals(1.0, bounds.getRightLongitude(), 0.00001);
-    assertEquals(0.0, bounds.getLeftLongitude(), 0.00001);
-  }
-  
-}
-
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoPathTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoPathTest.java b/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoPathTest.java
deleted file mode 100755
index fea7ed4..0000000
--- a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoPathTest.java
+++ /dev/null
@@ -1,270 +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.geo3d;
-
-import org.junit.Test;
-
-import static java.lang.Math.toRadians;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-public class GeoPathTest {
-
-  @Test
-  public void testPathDistance() {
-    // Start with a really simple case
-    GeoPath p;
-    GeoPoint gp;
-    p = new GeoPath(PlanetModel.SPHERE, 0.1);
-    p.addPoint(0.0, 0.0);
-    p.addPoint(0.0, 0.1);
-    p.addPoint(0.0, 0.2);
-    p.done();
-    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.5, 0.15);
-    assertEquals(Double.MAX_VALUE, p.computeDistance(DistanceStyle.ARC,gp), 0.0);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, 0.15);
-    assertEquals(0.15 + 0.05, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.12);
-    assertEquals(0.12 + 0.0, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.15, 0.05);
-    assertEquals(Double.MAX_VALUE, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.25);
-    assertEquals(0.20 + 0.05, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.05);
-    assertEquals(0.0 + 0.05, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
-
-    // Compute path distances now
-    p = new GeoPath(PlanetModel.SPHERE, 0.1);
-    p.addPoint(0.0, 0.0);
-    p.addPoint(0.0, 0.1);
-    p.addPoint(0.0, 0.2);
-    p.done();
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, 0.15);
-    assertEquals(0.15 + 0.05, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.12);
-    assertEquals(0.12, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
-
-    // Now try a vertical path, and make sure distances are as expected
-    p = new GeoPath(PlanetModel.SPHERE, 0.1);
-    p.addPoint(-Math.PI * 0.25, -0.5);
-    p.addPoint(Math.PI * 0.25, -0.5);
-    p.done();
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
-    assertEquals(Double.MAX_VALUE, p.computeDistance(DistanceStyle.ARC,gp), 0.0);
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -1.0);
-    assertEquals(Double.MAX_VALUE, p.computeDistance(DistanceStyle.ARC,gp), 0.0);
-    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.25 + 0.05, -0.5);
-    assertEquals(Math.PI * 0.5 + 0.05, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
-    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.25 - 0.05, -0.5);
-    assertEquals(0.0 + 0.05, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
-  }
-
-  @Test
-  public void testPathPointWithin() {
-    // Tests whether we can properly detect whether a point is within a path or not
-    GeoPath p;
-    GeoPoint gp;
-    p = new GeoPath(PlanetModel.SPHERE, 0.1);
-    // Build a diagonal path crossing the equator
-    p.addPoint(-0.2, -0.2);
-    p.addPoint(0.2, 0.2);
-    p.done();
-    // Test points on the path
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.2, -0.2);
-    assertTrue(p.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
-    assertTrue(p.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.1, 0.1);
-    assertTrue(p.isWithin(gp));
-    // Test points off the path
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.2, 0.2);
-    assertFalse(p.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0);
-    assertFalse(p.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.2, -0.2);
-    assertFalse(p.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
-    assertFalse(p.isWithin(gp));
-    // Repeat the test, but across the terminator
-    p = new GeoPath(PlanetModel.SPHERE, 0.1);
-    // Build a diagonal path crossing the equator
-    p.addPoint(-0.2, Math.PI - 0.2);
-    p.addPoint(0.2, -Math.PI + 0.2);
-    p.done();
-    // Test points on the path
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.2, Math.PI - 0.2);
-    assertTrue(p.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
-    assertTrue(p.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.1, -Math.PI + 0.1);
-    assertTrue(p.isWithin(gp));
-    // Test points off the path
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.2, -Math.PI + 0.2);
-    assertFalse(p.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0);
-    assertFalse(p.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.2, Math.PI - 0.2);
-    assertFalse(p.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
-    assertFalse(p.isWithin(gp));
-
-  }
-
-  @Test
-  public void testGetRelationship() {
-    GeoArea rect;
-    GeoPath p;
-    GeoPath c;
-    GeoPoint point;
-    GeoPoint pointApprox;
-    int relationship;
-    GeoArea area;
-    PlanetModel planetModel;
-    
-    planetModel = new PlanetModel(1.151145876105594, 0.8488541238944061);
-    c = new GeoPath(planetModel, 0.008726646259971648);
-    c.addPoint(-0.6925658899376476, 0.6316613927914589);
-    c.addPoint(0.27828548161836364, 0.6785795524104564);
-    c.done();
-    point = new GeoPoint(planetModel,-0.49298555067758226, 0.9892440995026406);
-    pointApprox = new GeoPoint(0.5110940362119821, 0.7774603209946239, -0.49984312299556544);
-    area = GeoAreaFactory.makeGeoArea(planetModel, 0.49937141144985997, 0.5161765426256085, 0.3337218719537796,0.8544419570901649, -0.6347692823688085, 0.3069696588119369);
-    assertTrue(!c.isWithin(point));
-    
-    // Start by testing the basic kinds of relationship, increasing in order of difficulty.
-
-    p = new GeoPath(PlanetModel.SPHERE, 0.1);
-    p.addPoint(-0.3, -0.3);
-    p.addPoint(0.3, 0.3);
-    p.done();
-    // Easiest: The path is wholly contains the georect
-    rect = new GeoRectangle(PlanetModel.SPHERE, 0.05, -0.05, -0.05, 0.05);
-    assertEquals(GeoArea.CONTAINS, rect.getRelationship(p));
-    // Next easiest: Some endpoints of the rectangle are inside, and some are outside.
-    rect = new GeoRectangle(PlanetModel.SPHERE, 0.05, -0.05, -0.05, 0.5);
-    assertEquals(GeoArea.OVERLAPS, rect.getRelationship(p));
-    // Now, all points are outside, but the figures intersect
-    rect = new GeoRectangle(PlanetModel.SPHERE, 0.05, -0.05, -0.5, 0.5);
-    assertEquals(GeoArea.OVERLAPS, rect.getRelationship(p));
-    // Finally, all points are outside, and the figures *do not* intersect
-    rect = new GeoRectangle(PlanetModel.SPHERE, 0.5, -0.5, -0.5, 0.5);
-    assertEquals(GeoArea.WITHIN, rect.getRelationship(p));
-    // Check that segment edge overlap detection works
-    rect = new GeoRectangle(PlanetModel.SPHERE, 0.1, 0.0, -0.1, 0.0);
-    assertEquals(GeoArea.OVERLAPS, rect.getRelationship(p));
-    rect = new GeoRectangle(PlanetModel.SPHERE, 0.2, 0.1, -0.2, -0.1);
-    assertEquals(GeoArea.DISJOINT, rect.getRelationship(p));
-    // Check if overlap at endpoints behaves as expected next
-    rect = new GeoRectangle(PlanetModel.SPHERE, 0.5, -0.5, -0.5, -0.35);
-    assertEquals(GeoArea.OVERLAPS, rect.getRelationship(p));
-    rect = new GeoRectangle(PlanetModel.SPHERE, 0.5, -0.5, -0.5, -0.45);
-    assertEquals(GeoArea.DISJOINT, rect.getRelationship(p));
-
-  }
-
-  @Test
-  public void testPathBounds() {
-    GeoPath c;
-    LatLonBounds b;
-    XYZBounds xyzb;
-    GeoPoint point;
-    int relationship;
-    GeoArea area;
-    PlanetModel planetModel;
-    
-    planetModel = new PlanetModel(0.751521665790406,1.248478334209594);
-    c = new GeoPath(planetModel, 0.7504915783575618);
-    c.addPoint(0.10869761172400265, 0.08895880215465272);
-    c.addPoint(0.22467878641991612, 0.10972973084229565);
-    c.addPoint(-0.7398772468744732, -0.4465812941383364);
-    c.addPoint(-0.18462055300079366, -0.6713857796763727);
-    c.done();
-    point = new GeoPoint(planetModel,-0.626645355125733,-1.409304625439381);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(planetModel,
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    relationship = area.getRelationship(c);
-    assertTrue(relationship == GeoArea.WITHIN || relationship == GeoArea.OVERLAPS);
-    assertTrue(area.isWithin(point));
-    // No longer true due to fixed GeoPath waypoints.
-    //assertTrue(c.isWithin(point));
-    
-    c = new GeoPath(PlanetModel.WGS84, 0.6894050545377601);
-    c.addPoint(-0.0788176065762948, 0.9431251741731624);
-    c.addPoint(0.510387871458147, 0.5327078872484678);
-    c.addPoint(-0.5624521609859962, 1.5398841746888388);
-    c.addPoint(-0.5025171434638661, -0.5895998642788894);
-    c.done();
-    point = new GeoPoint(PlanetModel.WGS84, 0.023652082107211682, 0.023131910152748437);
-    //System.err.println("Point.x = "+point.x+"; point.y="+point.y+"; point.z="+point.z);
-    assertTrue(c.isWithin(point));
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84,
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    //System.err.println("minx="+xyzb.getMinimumX()+" maxx="+xyzb.getMaximumX()+" miny="+xyzb.getMinimumY()+" maxy="+xyzb.getMaximumY()+" minz="+xyzb.getMinimumZ()+" maxz="+xyzb.getMaximumZ());
-    //System.err.println("point.x="+point.x+" point.y="+point.y+" point.z="+point.z);
-    relationship = area.getRelationship(c);
-    assertTrue(relationship == GeoArea.WITHIN || relationship == GeoArea.OVERLAPS);
-    assertTrue(area.isWithin(point));
-    
-    c = new GeoPath(PlanetModel.WGS84, 0.7766715171374766);
-    c.addPoint(-0.2751718361148076, -0.7786721269011477);
-    c.addPoint(0.5728375851539309, -1.2700115736820465);
-    c.done();
-    point = new GeoPoint(PlanetModel.WGS84, -0.01580760332365284, -0.03956004622490505);
-    assertTrue(c.isWithin(point));
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84,
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    //System.err.println("minx="+xyzb.getMinimumX()+" maxx="+xyzb.getMaximumX()+" miny="+xyzb.getMinimumY()+" maxy="+xyzb.getMaximumY()+" minz="+xyzb.getMinimumZ()+" maxz="+xyzb.getMaximumZ());
-    //System.err.println("point.x="+point.x+" point.y="+point.y+" point.z="+point.z);
-    relationship = area.getRelationship(c);
-    assertTrue(relationship == GeoArea.WITHIN || relationship == GeoArea.OVERLAPS);
-    assertTrue(area.isWithin(point));
-
-    c = new GeoPath(PlanetModel.SPHERE, 0.1);
-    c.addPoint(-0.3, -0.3);
-    c.addPoint(0.3, 0.3);
-    c.done();
-
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(-0.4046919, b.getLeftLongitude(), 0.000001);
-    assertEquals(0.4046919, b.getRightLongitude(), 0.000001);
-    assertEquals(-0.3999999, b.getMinLatitude(), 0.000001);
-    assertEquals(0.3999999, b.getMaxLatitude(), 0.000001);
-
-  }
-
-  @Test
-  public void testCoLinear() {
-    // p1: (12,-90), p2: (11, -55), (129, -90)
-    GeoPath p = new GeoPath(PlanetModel.SPHERE, 0.1);
-    p.addPoint(toRadians(-90), toRadians(12));//south pole
-    p.addPoint(toRadians(-55), toRadians(11));
-    p.addPoint(toRadians(-90), toRadians(129));//south pole again
-    p.done();//at least test this doesn't bomb like it used too -- LUCENE-6520
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoPolygonTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoPolygonTest.java b/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoPolygonTest.java
deleted file mode 100755
index f1511b9..0000000
--- a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoPolygonTest.java
+++ /dev/null
@@ -1,165 +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.geo3d;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-public class GeoPolygonTest {
-
-
-  @Test
-  public void testPolygonPointWithin() {
-    GeoMembershipShape c;
-    GeoPoint gp;
-    List<GeoPoint> points;
-
-    points = new ArrayList<GeoPoint>();
-    points.add(new GeoPoint(PlanetModel.SPHERE, -0.1, -0.5));
-    points.add(new GeoPoint(PlanetModel.SPHERE, 0.0, -0.6));
-    points.add(new GeoPoint(PlanetModel.SPHERE, 0.1, -0.5));
-    points.add(new GeoPoint(PlanetModel.SPHERE, 0.0, -0.4));
-
-    c = GeoPolygonFactory.makeGeoPolygon(PlanetModel.SPHERE, points, 0);
-    // Sample some points within
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.55);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.45);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.05, -0.5);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, -0.5);
-    assertTrue(c.isWithin(gp));
-    // Sample some nearby points outside
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.65);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.35);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.15, -0.5);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.15, -0.5);
-    assertFalse(c.isWithin(gp));
-    // Random points outside
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.5, 0.0);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
-    assertFalse(c.isWithin(gp));
-
-    points = new ArrayList<GeoPoint>();
-    points.add(new GeoPoint(PlanetModel.SPHERE, -0.1, -0.5));
-    points.add(new GeoPoint(PlanetModel.SPHERE, -0.01, -0.6));
-    points.add(new GeoPoint(PlanetModel.SPHERE, -0.1, -0.7));
-    points.add(new GeoPoint(PlanetModel.SPHERE, 0.0, -0.8));
-    points.add(new GeoPoint(PlanetModel.SPHERE, 0.1, -0.7));
-    points.add(new GeoPoint(PlanetModel.SPHERE, 0.01, -0.6));
-    points.add(new GeoPoint(PlanetModel.SPHERE, 0.1, -0.5));
-    points.add(new GeoPoint(PlanetModel.SPHERE, 0.0, -0.4));
-        
-        /*
-        System.out.println("Points: ");
-        for (GeoPoint p : points) {
-            System.out.println(" "+p);
-        }
-        */
-
-    c = GeoPolygonFactory.makeGeoPolygon(PlanetModel.SPHERE, points, 0);
-    // Sample some points within
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.55);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.45);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.05, -0.5);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, -0.5);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.7);
-    assertTrue(c.isWithin(gp));
-    // Sample some nearby points outside
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.35);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.15, -0.5);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.15, -0.5);
-    assertFalse(c.isWithin(gp));
-    // Random points outside
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.5, 0.0);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
-    assertFalse(c.isWithin(gp));
-
-  }
-
-  @Test
-  public void testPolygonBounds() {
-    GeoMembershipShape c;
-    LatLonBounds b;
-    List<GeoPoint> points;
-    XYZBounds xyzb;
-    GeoPoint point;
-    GeoArea area;
-    
-    // BKD failure
-    points = new ArrayList<GeoPoint>();
-    points.add(new GeoPoint(PlanetModel.WGS84, -0.36716183577912814, 1.4836349969188696));
-    points.add(new GeoPoint(PlanetModel.WGS84, 0.7846038240742979, -0.02743348424931823));
-    points.add(new GeoPoint(PlanetModel.WGS84, -0.7376479402362607, -0.5072961758807019));
-    points.add(new GeoPoint(PlanetModel.WGS84, -0.3760415907667887, 1.4970455334565513));
-    
-    c = GeoPolygonFactory.makeGeoPolygon(PlanetModel.WGS84, points, 1);
-    
-    point = new GeoPoint(PlanetModel.WGS84, -0.01580760332365284, -0.03956004622490505);
-    assertTrue(c.isWithin(point));
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84,
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    assertTrue(area.isWithin(point));
-    
-    points = new ArrayList<GeoPoint>();
-    points.add(new GeoPoint(PlanetModel.SPHERE, -0.1, -0.5));
-    points.add(new GeoPoint(PlanetModel.SPHERE, 0.0, -0.6));
-    points.add(new GeoPoint(PlanetModel.SPHERE, 0.1, -0.5));
-    points.add(new GeoPoint(PlanetModel.SPHERE, 0.0, -0.4));
-
-    c = GeoPolygonFactory.makeGeoPolygon(PlanetModel.SPHERE, points, 0);
-
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(-0.6, b.getLeftLongitude(), 0.000001);
-    assertEquals(-0.4, b.getRightLongitude(), 0.000001);
-    assertEquals(-0.1, b.getMinLatitude(), 0.000001);
-    assertEquals(0.1, b.getMaxLatitude(), 0.000001);
-  }
-
-}


[20/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 3a31a8c)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/SidedPlane.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/SidedPlane.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/SidedPlane.java
new file mode 100755
index 0000000..e080bc0
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/SidedPlane.java
@@ -0,0 +1,175 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Combination of a plane, and a sign value indicating what evaluation values are on the correct
+ * side of the plane.
+ *
+ * @lucene.experimental
+ */
+public class SidedPlane extends Plane implements Membership {
+  /** The sign value for evaluation of a point on the correct side of the plane */
+  public final double sigNum;
+
+  /**
+   * Construct a SidedPlane identical to an existing one, but reversed.
+   *
+   * @param sidedPlane is the existing plane.
+   */
+  public SidedPlane(SidedPlane sidedPlane) {
+    super(sidedPlane, sidedPlane.D);
+    this.sigNum = -sidedPlane.sigNum;
+  }
+
+  /**
+   * Construct a sided plane from a pair of vectors describing points, and including
+   * origin, plus a point p which describes the side.
+   *
+   * @param p point to evaluate
+   * @param A is the first in-plane point
+   * @param B is the second in-plane point
+   */
+  public SidedPlane(Vector p, Vector A, Vector B) {
+    super(A, B);
+    sigNum = Math.signum(evaluate(p));
+    if (sigNum == 0.0)
+      throw new IllegalArgumentException("Cannot determine sidedness because check point is on plane.");
+  }
+
+  /**
+   * Construct a sided plane from a point and a Z coordinate.
+   *
+   * @param p      point to evaluate.
+   * @param planetModel is the planet model.
+   * @param sinLat is the sin of the latitude of the plane.
+   */
+  public SidedPlane(Vector p, final PlanetModel planetModel, double sinLat) {
+    super(planetModel, sinLat);
+    sigNum = Math.signum(evaluate(p));
+    if (sigNum == 0.0)
+      throw new IllegalArgumentException("Cannot determine sidedness because check point is on plane.");
+  }
+
+  /**
+   * Construct a sided vertical plane from a point and specified x and y coordinates.
+   *
+   * @param p point to evaluate.
+   * @param x is the specified x.
+   * @param y is the specified y.
+   */
+  public SidedPlane(Vector p, double x, double y) {
+    super(x, y);
+    sigNum = Math.signum(evaluate(p));
+    if (sigNum == 0.0)
+      throw new IllegalArgumentException("Cannot determine sidedness because check point is on plane.");
+  }
+
+  /**
+   * Construct a sided plane with a normal vector and offset.
+   *
+   * @param p point to evaluate.
+   * @param v is the normal vector.
+   * @param D is the origin offset for the plan.
+   */
+  public SidedPlane(Vector p, Vector v, double D) {
+    super(v, D);
+    sigNum = Math.signum(evaluate(p));
+    if (sigNum == 0.0)
+      throw new IllegalArgumentException("Cannot determine sidedness because check point is on plane.");
+  }
+
+  /**
+   * Construct a sided plane with a normal vector and offset.
+   *
+   * @param pX X coord of point to evaluate.
+   * @param pY Y coord of point to evaluate.
+   * @param pZ Z coord of point to evaluate.
+   * @param v is the normal vector.
+   * @param D is the origin offset for the plan.
+   */
+  public SidedPlane(double pX, double pY, double pZ, Vector v, double D) {
+    super(v, D);
+    sigNum = Math.signum(evaluate(pX,pY,pZ));
+    if (sigNum == 0.0)
+      throw new IllegalArgumentException("Cannot determine sidedness because check point is on plane.");
+  }
+
+  /** Construct a sided plane from two points and a third normal vector.
+   */
+  public static SidedPlane constructNormalizedPerpendicularSidedPlane(final Vector insidePoint,
+    final Vector normalVector, final Vector point1, final Vector point2) {
+    final Vector pointsVector = new Vector(point1.x - point2.x, point1.y - point2.y, point1.z - point2.z);
+    final Vector newNormalVector = new Vector(normalVector, pointsVector);
+    try {
+      // To construct the plane, we now just need D, which is simply the negative of the evaluation of the circle normal vector at one of the points.
+      return new SidedPlane(insidePoint, newNormalVector, -newNormalVector.dotProduct(point1));
+    } catch (IllegalArgumentException e) {
+      return null;
+    }
+  }
+  
+  /** Construct a sided plane from three points.
+   */
+  public static SidedPlane constructNormalizedThreePointSidedPlane(final Vector insidePoint,
+    final Vector point1, final Vector point2, final Vector point3) {
+    try {
+      final Vector planeNormal = new Vector(
+        new Vector(point1.x - point2.x, point1.y - point2.y, point1.z - point2.z),
+        new Vector(point2.x - point3.x, point2.y - point3.y, point2.z - point3.z));
+      return new SidedPlane(insidePoint, planeNormal, -planeNormal.dotProduct(point2));
+    } catch (IllegalArgumentException e) {
+      return null;
+    }
+  }
+
+  @Override
+  public boolean isWithin(double x, double y, double z) {
+    double evalResult = evaluate(x, y, z);
+    if (Math.abs(evalResult) < MINIMUM_RESOLUTION)
+      return true;
+    double sigNum = Math.signum(evalResult);
+    return sigNum == this.sigNum;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (!(o instanceof SidedPlane)) return false;
+    if (!super.equals(o)) return false;
+
+    SidedPlane that = (SidedPlane) o;
+
+    return Double.compare(that.sigNum, sigNum) == 0;
+
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    long temp;
+    temp = Double.doubleToLongBits(sigNum);
+    result = 31 * result + (int) (temp ^ (temp >>> 32));
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "[A=" + x + ", B=" + y + ", C=" + z + ", D=" + D + ", side=" + sigNum + "]";
+  }
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/StandardXYZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/StandardXYZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/StandardXYZSolid.java
new file mode 100644
index 0000000..492f7b4
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/StandardXYZSolid.java
@@ -0,0 +1,417 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * 3D rectangle, bounded on six sides by X,Y,Z limits
+ *
+ * @lucene.internal
+ */
+public class StandardXYZSolid extends BaseXYZSolid {
+
+  /** Whole world? */
+  protected final boolean isWholeWorld;
+  /** Min-X plane */
+  protected final SidedPlane minXPlane;
+  /** Max-X plane */
+  protected final SidedPlane maxXPlane;
+  /** Min-Y plane */
+  protected final SidedPlane minYPlane;
+  /** Max-Y plane */
+  protected final SidedPlane maxYPlane;
+  /** Min-Z plane */
+  protected final SidedPlane minZPlane;
+  /** Max-Z plane */
+  protected final SidedPlane maxZPlane;
+  
+  /** These are the edge points of the shape, which are defined to be at least one point on
+   * each surface area boundary.  In the case of a solid, this includes points which represent
+   * the intersection of XYZ bounding planes and the planet, as well as points representing
+   * the intersection of single bounding planes with the planet itself.
+   */
+  protected final GeoPoint[] edgePoints;
+
+  /** Notable points for minXPlane */
+  protected final GeoPoint[] notableMinXPoints;
+  /** Notable points for maxXPlane */
+  protected final GeoPoint[] notableMaxXPoints;
+  /** Notable points for minYPlane */
+  protected final GeoPoint[] notableMinYPoints;
+  /** Notable points for maxYPlane */
+  protected final GeoPoint[] notableMaxYPoints;
+  /** Notable points for minZPlane */
+  protected final GeoPoint[] notableMinZPoints;
+  /** Notable points for maxZPlane */
+  protected final GeoPoint[] notableMaxZPoints;
+
+  /**
+   * Sole constructor
+   *
+   *@param planetModel is the planet model.
+   *@param minX is the minimum X value.
+   *@param maxX is the maximum X value.
+   *@param minY is the minimum Y value.
+   *@param maxY is the maximum Y value.
+   *@param minZ is the minimum Z value.
+   *@param maxZ is the maximum Z value.
+   */
+  public StandardXYZSolid(final PlanetModel planetModel,
+    final double minX,
+    final double maxX,
+    final double minY,
+    final double maxY,
+    final double minZ,
+    final double maxZ) {
+    super(planetModel);
+    // Argument checking
+    if (maxX - minX < Vector.MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("X values in wrong order or identical");
+    if (maxY - minY < Vector.MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("Y values in wrong order or identical");
+    if (maxZ - minZ < Vector.MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("Z values in wrong order or identical");
+
+    final double worldMinX = planetModel.getMinimumXValue();
+    final double worldMaxX = planetModel.getMaximumXValue();
+    final double worldMinY = planetModel.getMinimumYValue();
+    final double worldMaxY = planetModel.getMaximumYValue();
+    final double worldMinZ = planetModel.getMinimumZValue();
+    final double worldMaxZ = planetModel.getMaximumZValue();
+    
+    // We must distinguish between the case where the solid represents the entire world,
+    // and when the solid has no overlap with any part of the surface.  In both cases,
+    // there will be no edgepoints.
+    isWholeWorld =
+        (minX - worldMinX < -Vector.MINIMUM_RESOLUTION) &&
+        (maxX - worldMaxX > Vector.MINIMUM_RESOLUTION) &&
+        (minY - worldMinY < -Vector.MINIMUM_RESOLUTION) &&
+        (maxY - worldMaxY > Vector.MINIMUM_RESOLUTION) &&
+        (minZ - worldMinZ < -Vector.MINIMUM_RESOLUTION) &&
+        (maxZ - worldMaxZ > Vector.MINIMUM_RESOLUTION);
+
+    if (isWholeWorld) {
+      minXPlane = null;
+      maxXPlane = null;
+      minYPlane = null;
+      maxYPlane = null;
+      minZPlane = null;
+      maxZPlane = null;
+      notableMinXPoints = null;
+      notableMaxXPoints = null;
+      notableMinYPoints = null;
+      notableMaxYPoints = null;
+      notableMinZPoints = null;
+      notableMaxZPoints = null;
+      edgePoints = null;
+    } else {
+      // Construct the planes
+      minXPlane = new SidedPlane(maxX,0.0,0.0,xUnitVector,-minX);
+      maxXPlane = new SidedPlane(minX,0.0,0.0,xUnitVector,-maxX);
+      minYPlane = new SidedPlane(0.0,maxY,0.0,yUnitVector,-minY);
+      maxYPlane = new SidedPlane(0.0,minY,0.0,yUnitVector,-maxY);
+      minZPlane = new SidedPlane(0.0,0.0,maxZ,zUnitVector,-minZ);
+      maxZPlane = new SidedPlane(0.0,0.0,minZ,zUnitVector,-maxZ);
+      
+      // We need at least one point on the planet surface for each manifestation of the shape.
+      // There can be up to 2 (on opposite sides of the world).  But we have to go through
+      // 12 combinations of adjacent planes in order to find out if any have 2 intersection solution.
+      // Typically, this requires 12 square root operations. 
+      final GeoPoint[] minXminY = minXPlane.findIntersections(planetModel,minYPlane,maxXPlane,maxYPlane,minZPlane,maxZPlane);
+      final GeoPoint[] minXmaxY = minXPlane.findIntersections(planetModel,maxYPlane,maxXPlane,minYPlane,minZPlane,maxZPlane);
+      final GeoPoint[] minXminZ = minXPlane.findIntersections(planetModel,minZPlane,maxXPlane,maxZPlane,minYPlane,maxYPlane);
+      final GeoPoint[] minXmaxZ = minXPlane.findIntersections(planetModel,maxZPlane,maxXPlane,minZPlane,minYPlane,maxYPlane);
+
+      final GeoPoint[] maxXminY = maxXPlane.findIntersections(planetModel,minYPlane,minXPlane,maxYPlane,minZPlane,maxZPlane);
+      final GeoPoint[] maxXmaxY = maxXPlane.findIntersections(planetModel,maxYPlane,minXPlane,minYPlane,minZPlane,maxZPlane);
+      final GeoPoint[] maxXminZ = maxXPlane.findIntersections(planetModel,minZPlane,minXPlane,maxZPlane,minYPlane,maxYPlane);
+      final GeoPoint[] maxXmaxZ = maxXPlane.findIntersections(planetModel,maxZPlane,minXPlane,minZPlane,minYPlane,maxYPlane);
+      
+      final GeoPoint[] minYminZ = minYPlane.findIntersections(planetModel,minZPlane,maxYPlane,maxZPlane,minXPlane,maxXPlane);
+      final GeoPoint[] minYmaxZ = minYPlane.findIntersections(planetModel,maxZPlane,maxYPlane,minZPlane,minXPlane,maxXPlane);
+      final GeoPoint[] maxYminZ = maxYPlane.findIntersections(planetModel,minZPlane,minYPlane,maxZPlane,minXPlane,maxXPlane);
+      final GeoPoint[] maxYmaxZ = maxYPlane.findIntersections(planetModel,maxZPlane,minYPlane,minZPlane,minXPlane,maxXPlane);
+      
+      notableMinXPoints = glueTogether(minXminY, minXmaxY, minXminZ, minXmaxZ);
+      notableMaxXPoints = glueTogether(maxXminY, maxXmaxY, maxXminZ, maxXmaxZ);
+      notableMinYPoints = glueTogether(minXminY, maxXminY, minYminZ, minYmaxZ);
+      notableMaxYPoints = glueTogether(minXmaxY, maxXmaxY, maxYminZ, maxYmaxZ);
+      notableMinZPoints = glueTogether(minXminZ, maxXminZ, minYminZ, maxYminZ);
+      notableMaxZPoints = glueTogether(minXmaxZ, maxXmaxZ, minYmaxZ, maxYmaxZ);
+
+      // Now, compute the edge points.
+      // This is the trickiest part of setting up an XYZSolid.  We've computed intersections already, so
+      // we'll start there.
+      // There can be a number of shapes, each of which needs an edgepoint.  Each side by itself might contribute
+      // an edgepoint, for instance, if the plane describing that side intercepts the planet in such a way that the ellipse
+      // of interception does not meet any other planes.  Plane intersections can each contribute 0, 1, or 2 edgepoints.
+      //
+      // All of this makes for a lot of potential edgepoints, but I believe these can be pruned back with careful analysis.
+      // I haven't yet done that analysis, however, so I will treat them all as individual edgepoints.
+      
+      // The cases we are looking for are when the four corner points for any given
+      // plane are all outside of the world, AND that plane intersects the world.
+      // There are eight corner points all told; we must evaluate these WRT the planet surface.
+      final boolean minXminYminZ = planetModel.pointOutside(minX, minY, minZ);
+      final boolean minXminYmaxZ = planetModel.pointOutside(minX, minY, maxZ);
+      final boolean minXmaxYminZ = planetModel.pointOutside(minX, maxY, minZ);
+      final boolean minXmaxYmaxZ = planetModel.pointOutside(minX, maxY, maxZ);
+      final boolean maxXminYminZ = planetModel.pointOutside(maxX, minY, minZ);
+      final boolean maxXminYmaxZ = planetModel.pointOutside(maxX, minY, maxZ);
+      final boolean maxXmaxYminZ = planetModel.pointOutside(maxX, maxY, minZ);
+      final boolean maxXmaxYmaxZ = planetModel.pointOutside(maxX, maxY, maxZ);
+        
+      // Look at single-plane/world intersections.
+      // We detect these by looking at the world model and noting its x, y, and z bounds.
+
+      final GeoPoint[] minXEdges;
+      if (minX - worldMinX >= -Vector.MINIMUM_RESOLUTION && minX - worldMaxX <= Vector.MINIMUM_RESOLUTION &&
+        minY < 0.0 && maxY > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
+        minXminYminZ && minXminYmaxZ && minXmaxYminZ && minXmaxYmaxZ) {
+        // Find any point on the minX plane that intersects the world
+        // First construct a perpendicular plane that will allow us to find a sample point.
+        // This plane is vertical and goes through the points (0,0,0) and (1,0,0)
+        // Then use it to compute a sample point.
+        final GeoPoint intPoint = minXPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
+        if (intPoint != null) {
+          minXEdges = new GeoPoint[]{intPoint};
+        } else {
+          // No intersection found?
+          minXEdges = EMPTY_POINTS;
+        }
+      } else {
+        minXEdges = EMPTY_POINTS;
+      }
+      
+      final GeoPoint[] maxXEdges;
+      if (maxX - worldMinX >= -Vector.MINIMUM_RESOLUTION && maxX - worldMaxX <= Vector.MINIMUM_RESOLUTION &&
+        minY < 0.0 && maxY > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
+        maxXminYminZ && maxXminYmaxZ && maxXmaxYminZ && maxXmaxYmaxZ) {
+        // Find any point on the maxX plane that intersects the world
+        // First construct a perpendicular plane that will allow us to find a sample point.
+        // This plane is vertical and goes through the points (0,0,0) and (1,0,0)
+        // Then use it to compute a sample point.
+        final GeoPoint intPoint = maxXPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
+        if (intPoint != null) {
+          maxXEdges = new GeoPoint[]{intPoint};
+        } else {
+          maxXEdges = EMPTY_POINTS;
+        }
+      } else {
+        maxXEdges = EMPTY_POINTS;
+      }
+      
+      final GeoPoint[] minYEdges;
+      if (minY - worldMinY >= -Vector.MINIMUM_RESOLUTION && minY - worldMaxY <= Vector.MINIMUM_RESOLUTION &&
+        minX < 0.0 && maxX > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
+        minXminYminZ && minXminYmaxZ && maxXminYminZ && maxXminYmaxZ) {
+        // Find any point on the minY plane that intersects the world
+        // First construct a perpendicular plane that will allow us to find a sample point.
+        // This plane is vertical and goes through the points (0,0,0) and (0,1,0)
+        // Then use it to compute a sample point.
+        final GeoPoint intPoint = minYPlane.getSampleIntersectionPoint(planetModel, yVerticalPlane);
+        if (intPoint != null) {
+          minYEdges = new GeoPoint[]{intPoint};
+        } else {
+          minYEdges = EMPTY_POINTS;
+        }
+      } else {
+        minYEdges = EMPTY_POINTS;
+      }
+      
+      final GeoPoint[] maxYEdges;
+      if (maxY - worldMinY >= -Vector.MINIMUM_RESOLUTION && maxY - worldMaxY <= Vector.MINIMUM_RESOLUTION &&
+        minX < 0.0 && maxX > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
+        minXmaxYminZ && minXmaxYmaxZ && maxXmaxYminZ && maxXmaxYmaxZ) {
+        // Find any point on the maxY plane that intersects the world
+        // First construct a perpendicular plane that will allow us to find a sample point.
+        // This plane is vertical and goes through the points (0,0,0) and (0,1,0)
+        // Then use it to compute a sample point.
+        final GeoPoint intPoint = maxYPlane.getSampleIntersectionPoint(planetModel, yVerticalPlane);
+        if (intPoint != null) {
+          maxYEdges = new GeoPoint[]{intPoint};
+        } else {
+          maxYEdges = EMPTY_POINTS;
+        }
+      } else {
+        maxYEdges = EMPTY_POINTS;
+      }
+      
+      final GeoPoint[] minZEdges;
+      if (minZ - worldMinZ >= -Vector.MINIMUM_RESOLUTION && minZ - worldMaxZ <= Vector.MINIMUM_RESOLUTION &&
+        minX < 0.0 && maxX > 0.0 && minY < 0.0 && maxY > 0.0 &&
+        minXminYminZ && minXmaxYminZ && maxXminYminZ && maxXmaxYminZ) {
+        // Find any point on the minZ plane that intersects the world
+        // First construct a perpendicular plane that will allow us to find a sample point.
+        // This plane is vertical and goes through the points (0,0,0) and (1,0,0)
+        // Then use it to compute a sample point.
+        final GeoPoint intPoint = minZPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
+        if (intPoint != null) {
+          minZEdges = new GeoPoint[]{intPoint};
+        } else {
+          minZEdges = EMPTY_POINTS;
+        }
+      } else {
+        minZEdges = EMPTY_POINTS;
+      }
+      
+      final GeoPoint[] maxZEdges;
+      if (maxZ - worldMinZ >= -Vector.MINIMUM_RESOLUTION && maxZ - worldMaxZ <= Vector.MINIMUM_RESOLUTION &&
+        minX < 0.0 && maxX > 0.0 && minY < 0.0 && maxY > 0.0 &&
+        minXminYmaxZ && minXmaxYmaxZ && maxXminYmaxZ && maxXmaxYmaxZ) {
+        // Find any point on the maxZ plane that intersects the world
+        // First construct a perpendicular plane that will allow us to find a sample point.
+        // This plane is vertical and goes through the points (0,0,0) and (1,0,0) (that is, its orientation doesn't matter)
+        // Then use it to compute a sample point.
+        final GeoPoint intPoint = maxZPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
+        if (intPoint != null) {
+          maxZEdges = new GeoPoint[]{intPoint};
+        } else {
+          maxZEdges = EMPTY_POINTS;
+        }
+      } else {
+        maxZEdges = EMPTY_POINTS;
+      }
+      
+      // Glue everything together.  This is not a minimal set of edgepoints, as of now, but it does completely describe all shapes on the
+      // planet.
+      this.edgePoints = glueTogether(minXminY, minXmaxY, minXminZ, minXmaxZ,
+        maxXminY, maxXmaxY, maxXminZ, maxXmaxZ,
+        minYminZ, minYmaxZ, maxYminZ, maxYmaxZ,
+        minXEdges, maxXEdges, minYEdges, maxYEdges, minZEdges, maxZEdges);
+    }
+  }
+
+  @Override
+  protected GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+  
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    if (isWholeWorld) {
+      return true;
+    }
+    return minXPlane.isWithin(x, y, z) &&
+      maxXPlane.isWithin(x, y, z) &&
+      minYPlane.isWithin(x, y, z) &&
+      maxYPlane.isWithin(x, y, z) &&
+      minZPlane.isWithin(x, y, z) &&
+      maxZPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    if (isWholeWorld) {
+      if (path.getEdgePoints().length > 0)
+        return WITHIN;
+      return OVERLAPS;
+    }
+    
+    /*
+    for (GeoPoint p : getEdgePoints()) {
+      System.err.println(" Edge point "+p+" path.isWithin()? "+path.isWithin(p));
+    }
+    
+    for (GeoPoint p : path.getEdgePoints()) {
+      System.err.println(" path edge point "+p+" isWithin()? "+isWithin(p)+" minx="+minXPlane.evaluate(p)+" maxx="+maxXPlane.evaluate(p)+" miny="+minYPlane.evaluate(p)+" maxy="+maxYPlane.evaluate(p)+" minz="+minZPlane.evaluate(p)+" maxz="+maxZPlane.evaluate(p));
+    }
+    */
+    
+    //System.err.println(this+" getrelationship with "+path);
+    final int insideRectangle = isShapeInsideArea(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some shape points inside area");
+      return OVERLAPS;
+    }
+
+    // Figure out if the entire XYZArea is contained by the shape.
+    final int insideShape = isAreaInsideShape(path);
+    if (insideShape == SOME_INSIDE) {
+      //System.err.println(" some area points inside shape");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
+      //System.err.println(" inside of each other");
+      return OVERLAPS;
+    }
+
+    if (path.intersects(minXPlane, notableMinXPoints, maxXPlane, minYPlane, maxYPlane, minZPlane, maxZPlane) ||
+        path.intersects(maxXPlane, notableMaxXPoints, minXPlane, minYPlane, maxYPlane, minZPlane, maxZPlane) ||
+        path.intersects(minYPlane, notableMinYPoints, maxYPlane, minXPlane, maxXPlane, minZPlane, maxZPlane) ||
+        path.intersects(maxYPlane, notableMaxYPoints, minYPlane, minXPlane, maxXPlane, minZPlane, maxZPlane) ||
+        path.intersects(minZPlane, notableMinZPoints, maxZPlane, minXPlane, maxXPlane, minYPlane, maxYPlane) ||
+        path.intersects(maxZPlane, notableMaxZPoints, minZPlane, minXPlane, maxXPlane, minYPlane, maxYPlane)) {
+      //System.err.println(" edges intersect");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      //System.err.println(" all shape points inside area");
+      return WITHIN;
+    }
+
+    if (insideShape == ALL_INSIDE) {
+      //System.err.println(" all area points inside shape");
+      return CONTAINS;
+    }
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof StandardXYZSolid))
+      return false;
+    StandardXYZSolid other = (StandardXYZSolid) o;
+    if (!super.equals(other) ||
+      other.isWholeWorld != isWholeWorld) {
+      return false;
+    }
+    if (!isWholeWorld) {
+      return other.minXPlane.equals(minXPlane) &&
+        other.maxXPlane.equals(maxXPlane) &&
+        other.minYPlane.equals(minYPlane) &&
+        other.maxYPlane.equals(maxYPlane) &&
+        other.minZPlane.equals(minZPlane) &&
+        other.maxZPlane.equals(maxZPlane);
+    }
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + (isWholeWorld?1:0);
+    if (!isWholeWorld) {
+      result = 31 * result  + minXPlane.hashCode();
+      result = 31 * result  + maxXPlane.hashCode();
+      result = 31 * result  + minYPlane.hashCode();
+      result = 31 * result  + maxYPlane.hashCode();
+      result = 31 * result  + minZPlane.hashCode();
+      result = 31 * result  + maxZPlane.hashCode();
+    }
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "StandardXYZSolid: {planetmodel="+planetModel+", isWholeWorld="+isWholeWorld+", minXplane="+minXPlane+", maxXplane="+maxXPlane+", minYplane="+minYPlane+", maxYplane="+maxYPlane+", minZplane="+minZPlane+", maxZplane="+maxZPlane+"}";
+  }
+  
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Tools.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Tools.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Tools.java
new file mode 100755
index 0000000..e8ee29e
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Tools.java
@@ -0,0 +1,41 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Static methods globally useful for 3d geometric work.
+ *
+ * @lucene.experimental
+ */
+public class Tools {
+  private Tools() {
+  }
+
+  /**
+   * Java acos yields a NAN if you take an arc-cos of an
+   * angle that's just a tiny bit greater than 1.0, so
+   * here's a more resilient version.
+   */
+  public static double safeAcos(double value) {
+    if (value > 1.0)
+      value = 1.0;
+    else if (value < -1.0)
+      value = -1.0;
+    return Math.acos(value);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Vector.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Vector.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Vector.java
new file mode 100755
index 0000000..3a1b233
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Vector.java
@@ -0,0 +1,378 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * A 3d vector in space, not necessarily
+ * going through the origin.
+ *
+ * @lucene.experimental
+ */
+public class Vector {
+  /**
+   * Values that are all considered to be essentially zero have a magnitude
+   * less than this.
+   */
+  public static final double MINIMUM_RESOLUTION = 1.0e-12;
+  /**
+   * For squared quantities, the bound is squared too.
+   */
+  public static final double MINIMUM_RESOLUTION_SQUARED = MINIMUM_RESOLUTION * MINIMUM_RESOLUTION;
+  /**
+   * For cubed quantities, cube the bound.
+   */
+  public static final double MINIMUM_RESOLUTION_CUBED = MINIMUM_RESOLUTION_SQUARED * MINIMUM_RESOLUTION;
+
+  /** The x value */
+  public final double x;
+  /** The y value */
+  public final double y;
+  /** The z value */
+  public final double z;
+
+  /**
+   * Construct from (U.S.) x,y,z coordinates.
+   *@param x is the x value.
+   *@param y is the y value.
+   *@param z is the z value.
+   */
+  public Vector(double x, double y, double z) {
+    this.x = x;
+    this.y = y;
+    this.z = z;
+  }
+
+  /**
+   * Construct a vector that is perpendicular to
+   * two other (non-zero) vectors.  If the vectors are parallel,
+   * IllegalArgumentException will be thrown.
+   * Produces a normalized final vector.
+   *
+   * @param A is the first vector
+   * @param B is the second
+   */
+  public Vector(final Vector A, final Vector B) {
+    // x = u2v3 - u3v2
+    // y = u3v1 - u1v3
+    // z = u1v2 - u2v1
+    final double thisX = A.y * B.z - A.z * B.y;
+    final double thisY = A.z * B.x - A.x * B.z;
+    final double thisZ = A.x * B.y - A.y * B.x;
+    final double magnitude = magnitude(thisX, thisY, thisZ);
+    if (Math.abs(magnitude) < MINIMUM_RESOLUTION) {
+      throw new IllegalArgumentException("Degenerate/parallel vector constructed");
+    }
+    final double inverseMagnitude = 1.0 / magnitude;
+    this.x = thisX * inverseMagnitude;
+    this.y = thisY * inverseMagnitude;
+    this.z = thisZ * inverseMagnitude;
+  }
+
+  /** Compute a magnitude of an x,y,z value.
+   */
+  public static double magnitude(final double x, final double y, final double z) {
+    return Math.sqrt(x*x + y*y + z*z);
+  }
+  
+  /**
+   * Compute a normalized unit vector based on the current vector.
+   *
+   * @return the normalized vector, or null if the current vector has
+   * a magnitude of zero.
+   */
+  public Vector normalize() {
+    double denom = magnitude();
+    if (denom < MINIMUM_RESOLUTION)
+      // Degenerate, can't normalize
+      return null;
+    double normFactor = 1.0 / denom;
+    return new Vector(x * normFactor, y * normFactor, z * normFactor);
+  }
+
+  /**
+   * Do a dot product.
+   *
+   * @param v is the vector to multiply.
+   * @return the result.
+   */
+  public double dotProduct(final Vector v) {
+    return this.x * v.x + this.y * v.y + this.z * v.z;
+  }
+
+  /**
+   * Do a dot product.
+   *
+   * @param x is the x value of the vector to multiply.
+   * @param y is the y value of the vector to multiply.
+   * @param z is the z value of the vector to multiply.
+   * @return the result.
+   */
+  public double dotProduct(final double x, final double y, final double z) {
+    return this.x * x + this.y * y + this.z * z;
+  }
+
+  /**
+   * Determine if this vector, taken from the origin,
+   * describes a point within a set of planes.
+   *
+   * @param bounds     is the first part of the set of planes.
+   * @param moreBounds is the second part of the set of planes.
+   * @return true if the point is within the bounds.
+   */
+  public boolean isWithin(final Membership[] bounds, final Membership[] moreBounds) {
+    // Return true if the point described is within all provided bounds
+    //System.err.println("  checking if "+this+" is within bounds");
+    for (Membership bound : bounds) {
+      if (bound != null && !bound.isWithin(this)) {
+        //System.err.println("    NOT within "+bound);
+        return false;
+      }
+    }
+    for (Membership bound : moreBounds) {
+      if (bound != null && !bound.isWithin(this)) {
+        //System.err.println("    NOT within "+bound);
+        return false;
+      }
+    }
+    //System.err.println("    is within");
+    return true;
+  }
+
+  /**
+   * Translate vector.
+   */
+  public Vector translate(final double xOffset, final double yOffset, final double zOffset) {
+    return new Vector(x - xOffset, y - yOffset, z - zOffset);
+  }
+
+  /**
+   * Rotate vector counter-clockwise in x-y by an angle.
+   */
+  public Vector rotateXY(final double angle) {
+    return rotateXY(Math.sin(angle), Math.cos(angle));
+  }
+
+  /**
+   * Rotate vector counter-clockwise in x-y by an angle, expressed as sin and cos.
+   */
+  public Vector rotateXY(final double sinAngle, final double cosAngle) {
+    return new Vector(x * cosAngle - y * sinAngle, x * sinAngle + y * cosAngle, z);
+  }
+
+  /**
+   * Rotate vector counter-clockwise in x-z by an angle.
+   */
+  public Vector rotateXZ(final double angle) {
+    return rotateXZ(Math.sin(angle), Math.cos(angle));
+  }
+
+  /**
+   * Rotate vector counter-clockwise in x-z by an angle, expressed as sin and cos.
+   */
+  public Vector rotateXZ(final double sinAngle, final double cosAngle) {
+    return new Vector(x * cosAngle - z * sinAngle, y, x * sinAngle + z * cosAngle);
+  }
+
+  /**
+   * Rotate vector counter-clockwise in z-y by an angle.
+   */
+  public Vector rotateZY(final double angle) {
+    return rotateZY(Math.sin(angle), Math.cos(angle));
+  }
+
+  /**
+   * Rotate vector counter-clockwise in z-y by an angle, expressed as sin and cos.
+   */
+  public Vector rotateZY(final double sinAngle, final double cosAngle) {
+    return new Vector(x, z * sinAngle + y * cosAngle, z * cosAngle - y * sinAngle);
+  }
+
+  /**
+   * Compute the square of a straight-line distance to a point described by the
+   * vector taken from the origin.
+   * Monotonically increasing for arc distances up to PI.
+   *
+   * @param v is the vector to compute a distance to.
+   * @return the square of the linear distance.
+   */
+  public double linearDistanceSquared(final Vector v) {
+    double deltaX = this.x - v.x;
+    double deltaY = this.y - v.y;
+    double deltaZ = this.z - v.z;
+    return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
+  }
+
+  /**
+   * Compute the square of a straight-line distance to a point described by the
+   * vector taken from the origin.
+   * Monotonically increasing for arc distances up to PI.
+   *
+   * @param x is the x part of the vector to compute a distance to.
+   * @param y is the y part of the vector to compute a distance to.
+   * @param z is the z part of the vector to compute a distance to.
+   * @return the square of the linear distance.
+   */
+  public double linearDistanceSquared(final double x, final double y, final double z) {
+    double deltaX = this.x - x;
+    double deltaY = this.y - y;
+    double deltaZ = this.z - z;
+    return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
+  }
+
+  /**
+   * Compute the straight-line distance to a point described by the
+   * vector taken from the origin.
+   * Monotonically increasing for arc distances up to PI.
+   *
+   * @param v is the vector to compute a distance to.
+   * @return the linear distance.
+   */
+  public double linearDistance(final Vector v) {
+    return Math.sqrt(linearDistanceSquared(v));
+  }
+
+  /**
+   * Compute the straight-line distance to a point described by the
+   * vector taken from the origin.
+   * Monotonically increasing for arc distances up to PI.
+   *
+   * @param x is the x part of the vector to compute a distance to.
+   * @param y is the y part of the vector to compute a distance to.
+   * @param z is the z part of the vector to compute a distance to.
+   * @return the linear distance.
+   */
+  public double linearDistance(final double x, final double y, final double z) {
+    return Math.sqrt(linearDistanceSquared(x, y, z));
+  }
+
+  /**
+   * Compute the square of the normal distance to a vector described by a
+   * vector taken from the origin.
+   * Monotonically increasing for arc distances up to PI/2.
+   *
+   * @param v is the vector to compute a distance to.
+   * @return the square of the normal distance.
+   */
+  public double normalDistanceSquared(final Vector v) {
+    double t = dotProduct(v);
+    double deltaX = this.x * t - v.x;
+    double deltaY = this.y * t - v.y;
+    double deltaZ = this.z * t - v.z;
+    return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
+  }
+
+  /**
+   * Compute the square of the normal distance to a vector described by a
+   * vector taken from the origin.
+   * Monotonically increasing for arc distances up to PI/2.
+   *
+   * @param x is the x part of the vector to compute a distance to.
+   * @param y is the y part of the vector to compute a distance to.
+   * @param z is the z part of the vector to compute a distance to.
+   * @return the square of the normal distance.
+   */
+  public double normalDistanceSquared(final double x, final double y, final double z) {
+    double t = dotProduct(x, y, z);
+    double deltaX = this.x * t - x;
+    double deltaY = this.y * t - y;
+    double deltaZ = this.z * t - z;
+    return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
+  }
+
+  /**
+   * Compute the normal (perpendicular) distance to a vector described by a
+   * vector taken from the origin.
+   * Monotonically increasing for arc distances up to PI/2.
+   *
+   * @param v is the vector to compute a distance to.
+   * @return the normal distance.
+   */
+  public double normalDistance(final Vector v) {
+    return Math.sqrt(normalDistanceSquared(v));
+  }
+
+  /**
+   * Compute the normal (perpendicular) distance to a vector described by a
+   * vector taken from the origin.
+   * Monotonically increasing for arc distances up to PI/2.
+   *
+   * @param x is the x part of the vector to compute a distance to.
+   * @param y is the y part of the vector to compute a distance to.
+   * @param z is the z part of the vector to compute a distance to.
+   * @return the normal distance.
+   */
+  public double normalDistance(final double x, final double y, final double z) {
+    return Math.sqrt(normalDistanceSquared(x, y, z));
+  }
+
+  /**
+   * Compute the magnitude of this vector.
+   *
+   * @return the magnitude.
+   */
+  public double magnitude() {
+    return magnitude(x,y,z);
+  }
+
+  /** Compute the desired magnitude of a unit vector projected to a given
+   * planet model.
+   * @param planetModel is the planet model.
+   * @param x is the unit vector x value.
+   * @param y is the unit vector y value.
+   * @param z is the unit vector z value.
+   * @return a magnitude value for that (x,y,z) that projects the vector onto the specified ellipsoid.
+   */
+  protected static double computeDesiredEllipsoidMagnitude(final PlanetModel planetModel, final double x, final double y, final double z) {
+    return 1.0 / Math.sqrt(x*x*planetModel.inverseAbSquared + y*y*planetModel.inverseAbSquared + z*z*planetModel.inverseCSquared);
+  }
+
+  /** Compute the desired magnitude of a unit vector projected to a given
+   * planet model.  The unit vector is specified only by a z value.
+   * @param planetModel is the planet model.
+   * @param z is the unit vector z value.
+   * @return a magnitude value for that z value that projects the vector onto the specified ellipsoid.
+   */
+  protected static double computeDesiredEllipsoidMagnitude(final PlanetModel planetModel, final double z) {
+    return 1.0 / Math.sqrt((1.0-z*z)*planetModel.inverseAbSquared + z*z*planetModel.inverseCSquared);
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof Vector))
+      return false;
+    Vector other = (Vector) o;
+    return (other.x == x && other.y == y && other.z == z);
+  }
+
+  @Override
+  public int hashCode() {
+    int result;
+    long temp;
+    temp = Double.doubleToLongBits(x);
+    result = (int) (temp ^ (temp >>> 32));
+    temp = Double.doubleToLongBits(y);
+    result = 31 * result + (int) (temp ^ (temp >>> 32));
+    temp = Double.doubleToLongBits(z);
+    result = 31 * result + (int) (temp ^ (temp >>> 32));
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "[X=" + x + ", Y=" + y + ", Z=" + z + "]";
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYZBounds.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYZBounds.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYZBounds.java
new file mode 100644
index 0000000..c3ee53d
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYZBounds.java
@@ -0,0 +1,267 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * An object for accumulating XYZ bounds information.
+ *
+ * @lucene.experimental
+ */
+public class XYZBounds implements Bounds {
+
+  /** A 'fudge factor', which is added to maximums and subtracted from minimums,
+   * in order to compensate for potential error deltas.  This would not be necessary
+   * except that our 'bounds' is defined as always equaling or exceeding the boundary
+   * of the shape, and we cannot guarantee that without making MINIMUM_RESOLUTION
+   * unacceptably large.
+   */
+  protected static final double FUDGE_FACTOR = Vector.MINIMUM_RESOLUTION * 2.0;
+  
+  /** Minimum x */
+  protected Double minX = null;
+  /** Maximum x */
+  protected Double maxX = null;
+  /** Minimum y */
+  protected Double minY = null;
+  /** Maximum y */
+  protected Double maxY = null;
+  /** Minimum z */
+  protected Double minZ = null;
+  /** Maximum z */
+  protected Double maxZ = null;
+  
+  /** Set to true if no longitude bounds can be stated */
+  protected boolean noLongitudeBound = false;
+  /** Set to true if no top latitude bound can be stated */
+  protected boolean noTopLatitudeBound = false;
+  /** Set to true if no bottom latitude bound can be stated */
+  protected boolean noBottomLatitudeBound = false;
+
+  /** Construct an empty bounds object */
+  public XYZBounds() {
+  }
+
+  // Accessor methods
+  
+  /** Return the minimum X value.
+   *@return minimum X value.
+   */
+  public Double getMinimumX() {
+    return minX;
+  }
+
+  /** Return the maximum X value.
+   *@return maximum X value.
+   */
+  public Double getMaximumX() {
+    return maxX;
+  }
+
+  /** Return the minimum Y value.
+   *@return minimum Y value.
+   */
+  public Double getMinimumY() {
+    return minY;
+  }
+
+  /** Return the maximum Y value.
+   *@return maximum Y value.
+   */
+  public Double getMaximumY() {
+    return maxY;
+  }
+  
+  /** Return the minimum Z value.
+   *@return minimum Z value.
+   */
+  public Double getMinimumZ() {
+    return minZ;
+  }
+
+  /** Return the maximum Z value.
+   *@return maximum Z value.
+   */
+  public Double getMaximumZ() {
+    return maxZ;
+  }
+
+  /** Return true if minX is as small as the planet model allows.
+   *@return true if minX has reached its bound.
+   */
+  public boolean isSmallestMinX(final PlanetModel planetModel) {
+    if (minX == null)
+      return false;
+    return minX - planetModel.getMinimumXValue() < Vector.MINIMUM_RESOLUTION;
+  }
+  
+  /** Return true if maxX is as large as the planet model allows.
+   *@return true if maxX has reached its bound.
+   */
+  public boolean isLargestMaxX(final PlanetModel planetModel) {
+    if (maxX == null)
+      return false;
+    return planetModel.getMaximumXValue() - maxX < Vector.MINIMUM_RESOLUTION;
+  }
+
+  /** Return true if minY is as small as the planet model allows.
+   *@return true if minY has reached its bound.
+   */
+  public boolean isSmallestMinY(final PlanetModel planetModel) {
+    if (minY == null)
+      return false;
+    return minY - planetModel.getMinimumYValue() < Vector.MINIMUM_RESOLUTION;
+  }
+  
+  /** Return true if maxY is as large as the planet model allows.
+   *@return true if maxY has reached its bound.
+   */
+  public boolean isLargestMaxY(final PlanetModel planetModel) {
+    if (maxY == null)
+      return false;
+    return planetModel.getMaximumYValue() - maxY < Vector.MINIMUM_RESOLUTION;
+  }
+  
+  /** Return true if minZ is as small as the planet model allows.
+   *@return true if minZ has reached its bound.
+   */
+  public boolean isSmallestMinZ(final PlanetModel planetModel) {
+    if (minZ == null)
+      return false;
+    return minZ - planetModel.getMinimumZValue() < Vector.MINIMUM_RESOLUTION;
+  }
+  
+  /** Return true if maxZ is as large as the planet model allows.
+   *@return true if maxZ has reached its bound.
+   */
+  public boolean isLargestMaxZ(final PlanetModel planetModel) {
+    if (maxZ == null)
+      return false;
+    return planetModel.getMaximumZValue() - maxZ < Vector.MINIMUM_RESOLUTION;
+  }
+
+  // Modification methods
+  
+  @Override
+  public Bounds addPlane(final PlanetModel planetModel, final Plane plane, final Membership... bounds) {
+    plane.recordBounds(planetModel, this, bounds);
+    return this;
+  }
+
+  /** Add a horizontal plane to the bounds description.
+   * This method should EITHER use the supplied latitude, OR use the supplied
+   * plane, depending on what is most efficient.
+   *@param planetModel is the planet model.
+   *@param latitude is the latitude.
+   *@param horizontalPlane is the plane.
+   *@param bounds are the constraints on the plane.
+   *@return updated Bounds object.
+   */
+  public Bounds addHorizontalPlane(final PlanetModel planetModel,
+    final double latitude,
+    final Plane horizontalPlane,
+    final Membership... bounds) {
+    return addPlane(planetModel, horizontalPlane, bounds);
+  }
+    
+  /** Add a vertical plane to the bounds description.
+   * This method should EITHER use the supplied longitude, OR use the supplied
+   * plane, depending on what is most efficient.
+   *@param planetModel is the planet model.
+   *@param longitude is the longitude.
+   *@param verticalPlane is the plane.
+   *@param bounds are the constraints on the plane.
+   *@return updated Bounds object.
+   */
+  public Bounds addVerticalPlane(final PlanetModel planetModel,
+    final double longitude,
+    final Plane verticalPlane,
+    final Membership... bounds) {
+    return addPlane(planetModel, verticalPlane, bounds);
+  }
+
+  @Override
+  public Bounds addXValue(final GeoPoint point) {
+    final double x = point.x;
+    final double small = x - FUDGE_FACTOR;
+    if (minX == null || minX > small) {
+      minX = new Double(small);
+    }
+    final double large = x + FUDGE_FACTOR;
+    if (maxX == null || maxX < large) {
+      maxX = new Double(large);
+    }
+    return this;
+  }
+
+  @Override
+  public Bounds addYValue(final GeoPoint point) {
+    final double y = point.y;
+    final double small = y - FUDGE_FACTOR;
+    if (minY == null || minY > small) {
+      minY = new Double(small);
+    }
+    final double large = y + FUDGE_FACTOR;
+    if (maxY == null || maxY < large) {
+      maxY = new Double(large);
+    }
+    return this;
+  }
+
+  @Override
+  public Bounds addZValue(final GeoPoint point) {
+    final double z = point.z;
+    final double small = z - FUDGE_FACTOR;
+    if (minZ == null || minZ > small) {
+      minZ = new Double(small);
+    }
+    final double large = z + FUDGE_FACTOR;
+    if (maxZ == null || maxZ < large) {
+      maxZ = new Double(large);
+    }
+    return this;
+  }
+
+  @Override
+  public Bounds addPoint(final GeoPoint point) {
+    return addXValue(point).addYValue(point).addZValue(point);
+  }
+
+  @Override
+  public Bounds isWide() {
+    // No specific thing we need to do.
+    return this;
+  }
+
+  @Override
+  public Bounds noLongitudeBound() {
+    // No specific thing we need to do.
+    return this;
+  }
+
+  @Override
+  public Bounds noTopLatitudeBound() {
+    // No specific thing we need to do.
+    return this;
+  }
+
+  @Override
+  public Bounds noBottomLatitudeBound() {
+    // No specific thing we need to do.
+    return this;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYZSolid.java
new file mode 100644
index 0000000..9298079
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYZSolid.java
@@ -0,0 +1,26 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Interface for a family of 3D rectangles, bounded on six sides by X,Y,Z limits
+ *
+ * @lucene.internal
+ */
+public interface XYZSolid extends GeoArea {
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYZSolidFactory.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYZSolidFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYZSolidFactory.java
new file mode 100644
index 0000000..25ea400
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYZSolidFactory.java
@@ -0,0 +1,67 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Factory for {@link XYZSolid}.
+ *
+ * @lucene.experimental
+ */
+public class XYZSolidFactory {
+  private XYZSolidFactory() {
+  }
+
+  /**
+   * Create a XYZSolid of the right kind given (x,y,z) bounds.
+   * @param planetModel is the planet model
+   * @param minX is the min X boundary
+   * @param maxX is the max X boundary
+   * @param minY is the min Y boundary
+   * @param maxY is the max Y boundary
+   * @param minZ is the min Z boundary
+   * @param maxZ is the max Z boundary
+   */
+  public static XYZSolid makeXYZSolid(final PlanetModel planetModel, final double minX, final double maxX, final double minY, final double maxY, final double minZ, final double maxZ) {
+    if (Math.abs(maxX - minX) < Vector.MINIMUM_RESOLUTION) {
+      if (Math.abs(maxY - minY) < Vector.MINIMUM_RESOLUTION) {
+        if (Math.abs(maxZ - minZ) < Vector.MINIMUM_RESOLUTION) {
+          return new dXdYdZSolid(planetModel, (minX+maxX) * 0.5, (minY+maxY) * 0.5, minZ);
+        } else {
+          return new dXdYZSolid(planetModel, (minX+maxX) * 0.5, (minY+maxY) * 0.5, minZ, maxZ);
+        }
+      } else {
+        if (Math.abs(maxZ - minZ) < Vector.MINIMUM_RESOLUTION) {
+          return new dXYdZSolid(planetModel, (minX+maxX) * 0.5, minY, maxY, (minZ+maxZ) * 0.5);
+        } else {
+          return new dXYZSolid(planetModel, (minX+maxX) * 0.5, minY, maxY, minZ, maxZ);
+        }
+      }
+    }
+    if (Math.abs(maxY - minY) < Vector.MINIMUM_RESOLUTION) {
+      if (Math.abs(maxZ - minZ) < Vector.MINIMUM_RESOLUTION) {
+        return new XdYdZSolid(planetModel, minX, maxX, (minY+maxY) * 0.5, (minZ+maxZ) * 0.5);
+      } else {
+        return new XdYZSolid(planetModel, minX, maxX, (minY+maxY) * 0.5, minZ, maxZ);
+      }
+    }
+    if (Math.abs(maxZ - minZ) < Vector.MINIMUM_RESOLUTION) {
+      return new XYdZSolid(planetModel, minX, maxX, minY, maxY, (minZ+maxZ) * 0.5);
+    }
+    return new StandardXYZSolid(planetModel, minX, maxX, minY, maxY, minZ, maxZ);
+  }
+  
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYdZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYdZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYdZSolid.java
new file mode 100644
index 0000000..66aac84
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYdZSolid.java
@@ -0,0 +1,213 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in Z
+ *
+ * @lucene.internal
+ */
+public class XYdZSolid extends BaseXYZSolid {
+
+  /** Min-X plane */
+  protected final SidedPlane minXPlane;
+  /** Max-X plane */
+  protected final SidedPlane maxXPlane;
+  /** Min-Y plane */
+  protected final SidedPlane minYPlane;
+  /** Max-Y plane */
+  protected final SidedPlane maxYPlane;
+  /** Z plane */
+  protected final Plane zPlane;
+  
+  /** These are the edge points of the shape, which are defined to be at least one point on
+   * each surface area boundary.  In the case of a solid, this includes points which represent
+   * the intersection of XYZ bounding planes and the planet, as well as points representing
+   * the intersection of single bounding planes with the planet itself.
+   */
+  protected final GeoPoint[] edgePoints;
+
+  /** Notable points for ZPlane */
+  protected final GeoPoint[] notableZPoints;
+
+  /**
+   * Sole constructor
+   *
+   *@param planetModel is the planet model.
+   *@param minX is the minimum X value.
+   *@param maxX is the maximum X value.
+   *@param minY is the minimum Y value.
+   *@param maxY is the maximum Y value.
+   *@param Z is the Z value.
+   */
+  public XYdZSolid(final PlanetModel planetModel,
+    final double minX,
+    final double maxX,
+    final double minY,
+    final double maxY,
+    final double Z) {
+    super(planetModel);
+    // Argument checking
+    if (maxX - minX < Vector.MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("X values in wrong order or identical");
+    if (maxY - minY < Vector.MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("Y values in wrong order or identical");
+
+    final double worldMinZ = planetModel.getMinimumZValue();
+    final double worldMaxZ = planetModel.getMaximumZValue();
+    
+    // Construct the planes
+    minXPlane = new SidedPlane(maxX,0.0,0.0,xUnitVector,-minX);
+    maxXPlane = new SidedPlane(minX,0.0,0.0,xUnitVector,-maxX);
+    minYPlane = new SidedPlane(0.0,maxY,0.0,yUnitVector,-minY);
+    maxYPlane = new SidedPlane(0.0,minY,0.0,yUnitVector,-maxY);
+    zPlane = new Plane(zUnitVector,-Z);
+      
+    // We need at least one point on the planet surface for each manifestation of the shape.
+    // There can be up to 2 (on opposite sides of the world).  But we have to go through
+    // 4 combinations of adjacent planes in order to find out if any have 2 intersection solution.
+    // Typically, this requires 4 square root operations. 
+    final GeoPoint[] minXZ = minXPlane.findIntersections(planetModel,zPlane,maxXPlane,minYPlane,maxYPlane);
+    final GeoPoint[] maxXZ = maxXPlane.findIntersections(planetModel,zPlane,minXPlane,minYPlane,maxYPlane);
+    final GeoPoint[] minYZ = minYPlane.findIntersections(planetModel,zPlane,maxYPlane,minXPlane,maxXPlane);
+    final GeoPoint[] maxYZ = maxYPlane.findIntersections(planetModel,zPlane,minYPlane,minXPlane,maxXPlane);
+      
+    notableZPoints = glueTogether(minXZ, maxXZ, minYZ, maxYZ);
+
+    // Now, compute the edge points.
+    // This is the trickiest part of setting up an XYZSolid.  We've computed intersections already, so
+    // we'll start there.  We know that at most there will be two disconnected shapes on the planet surface.
+    // But there's also a case where exactly one plane slices through the world, and none of the bounding plane
+    // intersections do.  Thus, if we don't find any of the edge intersection cases, we have to look for that last case.
+      
+    // If we still haven't encountered anything, we need to look at single-plane/world intersections.
+    // We detect these by looking at the world model and noting its x, y, and z bounds.
+    // The cases we are looking for are when the four corner points for any given
+    // plane are all outside of the world, AND that plane intersects the world.
+    // There are four corner points all told; we must evaluate these WRT the planet surface.
+    final boolean minXminYZ = planetModel.pointOutside(minX, minY, Z);
+    final boolean minXmaxYZ = planetModel.pointOutside(minX, maxY, Z);
+    final boolean maxXminYZ = planetModel.pointOutside(maxX, minY, Z);
+    final boolean maxXmaxYZ = planetModel.pointOutside(maxX, maxY, Z);
+
+    final GeoPoint[] zEdges;
+    if (Z - worldMinZ >= -Vector.MINIMUM_RESOLUTION && Z - worldMaxZ <= Vector.MINIMUM_RESOLUTION &&
+      minX < 0.0 && maxX > 0.0 && minY < 0.0 && maxY > 0.0 &&
+      minXminYZ && minXmaxYZ && maxXminYZ && maxXmaxYZ) {
+      // Find any point on the minZ plane that intersects the world
+      // First construct a perpendicular plane that will allow us to find a sample point.
+      // This plane is vertical and goes through the points (0,0,0) and (1,0,0)
+      // Then use it to compute a sample point.
+      final GeoPoint intPoint = zPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
+      if (intPoint != null) {
+        zEdges = new GeoPoint[]{intPoint};
+      } else {
+        zEdges = EMPTY_POINTS;
+      }
+    } else {
+      zEdges= EMPTY_POINTS;
+    }
+
+    this.edgePoints = glueTogether(minXZ, maxXZ, minYZ, maxYZ, zEdges);
+  }
+
+  @Override
+  protected GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+  
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return minXPlane.isWithin(x, y, z) &&
+      maxXPlane.isWithin(x, y, z) &&
+      minYPlane.isWithin(x, y, z) &&
+      maxYPlane.isWithin(x, y, z) &&
+      zPlane.evaluateIsZero(x, y, z);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    
+    //System.err.println(this+" getrelationship with "+path);
+    final int insideRectangle = isShapeInsideArea(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some inside");
+      return OVERLAPS;
+    }
+
+    // Figure out if the entire XYZArea is contained by the shape.
+    final int insideShape = isAreaInsideShape(path);
+    if (insideShape == SOME_INSIDE) {
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
+      //System.err.println(" inside of each other");
+      return OVERLAPS;
+    }
+
+    if (path.intersects(zPlane, notableZPoints, minXPlane, maxXPlane, minYPlane, maxYPlane)) {
+      //System.err.println(" edges intersect");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      //System.err.println(" shape inside rectangle");
+      return WITHIN;
+    }
+
+    if (insideShape == ALL_INSIDE) {
+      //System.err.println(" shape contains rectangle");
+      return CONTAINS;
+    }
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof XYdZSolid))
+      return false;
+    XYdZSolid other = (XYdZSolid) o;
+    if (!super.equals(other)) {
+      return false;
+    }
+    return other.minXPlane.equals(minXPlane) &&
+      other.maxXPlane.equals(maxXPlane) &&
+      other.minYPlane.equals(minYPlane) &&
+      other.maxYPlane.equals(maxYPlane) &&
+      other.zPlane.equals(zPlane);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result  + minXPlane.hashCode();
+    result = 31 * result  + maxXPlane.hashCode();
+    result = 31 * result  + minYPlane.hashCode();
+    result = 31 * result  + maxYPlane.hashCode();
+    result = 31 * result  + zPlane.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "XYdZSolid: {planetmodel="+planetModel+", minXplane="+minXPlane+", maxXplane="+maxXPlane+", minYplane="+minYPlane+", maxYplane="+maxYPlane+", zplane="+zPlane+"}";
+  }
+  
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XdYZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XdYZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XdYZSolid.java
new file mode 100644
index 0000000..d9e11b8
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XdYZSolid.java
@@ -0,0 +1,212 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in Y
+ *
+ * @lucene.internal
+ */
+public class XdYZSolid extends BaseXYZSolid {
+
+  /** Min-X plane */
+  protected final SidedPlane minXPlane;
+  /** Max-X plane */
+  protected final SidedPlane maxXPlane;
+  /** Y plane */
+  protected final Plane yPlane;
+  /** Min-Z plane */
+  protected final SidedPlane minZPlane;
+  /** Max-Z plane */
+  protected final SidedPlane maxZPlane;
+  
+  /** These are the edge points of the shape, which are defined to be at least one point on
+   * each surface area boundary.  In the case of a solid, this includes points which represent
+   * the intersection of XYZ bounding planes and the planet, as well as points representing
+   * the intersection of single bounding planes with the planet itself.
+   */
+  protected final GeoPoint[] edgePoints;
+
+  /** Notable points for YPlane */
+  protected final GeoPoint[] notableYPoints;
+
+  /**
+   * Sole constructor
+   *
+   *@param planetModel is the planet model.
+   *@param minX is the minimum X value.
+   *@param maxX is the maximum X value.
+   *@param Y is the Y value.
+   *@param minZ is the minimum Z value.
+   *@param maxZ is the maximum Z value.
+   */
+  public XdYZSolid(final PlanetModel planetModel,
+    final double minX,
+    final double maxX,
+    final double Y,
+    final double minZ,
+    final double maxZ) {
+    super(planetModel);
+    // Argument checking
+    if (maxX - minX < Vector.MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("X values in wrong order or identical");
+    if (maxZ - minZ < Vector.MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("Z values in wrong order or identical");
+
+    final double worldMinY = planetModel.getMinimumYValue();
+    final double worldMaxY = planetModel.getMaximumYValue();
+    
+    // Construct the planes
+    minXPlane = new SidedPlane(maxX,0.0,0.0,xUnitVector,-minX);
+    maxXPlane = new SidedPlane(minX,0.0,0.0,xUnitVector,-maxX);
+    yPlane = new Plane(yUnitVector,-Y);
+    minZPlane = new SidedPlane(0.0,0.0,maxZ,zUnitVector,-minZ);
+    maxZPlane = new SidedPlane(0.0,0.0,minZ,zUnitVector,-maxZ);
+      
+    // We need at least one point on the planet surface for each manifestation of the shape.
+    // There can be up to 2 (on opposite sides of the world).  But we have to go through
+    // 4 combinations of adjacent planes in order to find out if any have 2 intersection solution.
+    // Typically, this requires 4 square root operations. 
+    final GeoPoint[] minXY = minXPlane.findIntersections(planetModel,yPlane,maxXPlane,minZPlane,maxZPlane);
+    final GeoPoint[] maxXY = maxXPlane.findIntersections(planetModel,yPlane,minXPlane,minZPlane,maxZPlane);
+    final GeoPoint[] YminZ = yPlane.findIntersections(planetModel,minZPlane,maxZPlane,minXPlane,maxXPlane);
+    final GeoPoint[] YmaxZ = yPlane.findIntersections(planetModel,maxZPlane,minZPlane,minXPlane,maxXPlane);
+      
+    notableYPoints = glueTogether(minXY, maxXY, YminZ, YmaxZ);
+
+    // Now, compute the edge points.
+    // This is the trickiest part of setting up an XYZSolid.  We've computed intersections already, so
+    // we'll start there.  We know that at most there will be two disconnected shapes on the planet surface.
+    // But there's also a case where exactly one plane slices through the world, and none of the bounding plane
+    // intersections do.  Thus, if we don't find any of the edge intersection cases, we have to look for that last case.
+      
+    // We need to look at single-plane/world intersections.
+    // We detect these by looking at the world model and noting its x, y, and z bounds.
+    // The cases we are looking for are when the four corner points for any given
+    // plane are all outside of the world, AND that plane intersects the world.
+    // There are four corner points all told; we must evaluate these WRT the planet surface.
+    final boolean minXYminZ = planetModel.pointOutside(minX, Y, minZ);
+    final boolean minXYmaxZ = planetModel.pointOutside(minX, Y, maxZ);
+    final boolean maxXYminZ = planetModel.pointOutside(maxX, Y, minZ);
+    final boolean maxXYmaxZ = planetModel.pointOutside(maxX, Y, maxZ);
+
+    final GeoPoint[] yEdges;
+    if (Y - worldMinY >= -Vector.MINIMUM_RESOLUTION && Y - worldMaxY <= Vector.MINIMUM_RESOLUTION &&
+      minX < 0.0 && maxX > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
+      minXYminZ && minXYmaxZ && maxXYminZ && maxXYmaxZ) {
+      // Find any point on the minY plane that intersects the world
+      // First construct a perpendicular plane that will allow us to find a sample point.
+      // This plane is vertical and goes through the points (0,0,0) and (0,1,0)
+      // Then use it to compute a sample point.
+      final GeoPoint intPoint = yPlane.getSampleIntersectionPoint(planetModel, yVerticalPlane);
+      if (intPoint != null) {
+        yEdges = new GeoPoint[]{intPoint};
+      } else {
+        yEdges = EMPTY_POINTS;
+      }
+    } else {
+      yEdges = EMPTY_POINTS;
+    }
+
+    this.edgePoints = glueTogether(minXY, maxXY, YminZ, YmaxZ, yEdges);
+  }
+
+  @Override
+  protected GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+  
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return minXPlane.isWithin(x, y, z) &&
+      maxXPlane.isWithin(x, y, z) &&
+      yPlane.evaluateIsZero(x, y, z) &&
+      minZPlane.isWithin(x, y, z) &&
+      maxZPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    //System.err.println(this+" getrelationship with "+path);
+    final int insideRectangle = isShapeInsideArea(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some inside");
+      return OVERLAPS;
+    }
+
+    // Figure out if the entire XYZArea is contained by the shape.
+    final int insideShape = isAreaInsideShape(path);
+    if (insideShape == SOME_INSIDE) {
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
+      //System.err.println(" inside of each other");
+      return OVERLAPS;
+    }
+
+    if (path.intersects(yPlane, notableYPoints, minXPlane, maxXPlane, minZPlane, maxZPlane)) {
+      //System.err.println(" edges intersect");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      //System.err.println(" shape inside rectangle");
+      return WITHIN;
+    }
+
+    if (insideShape == ALL_INSIDE) {
+      //System.err.println(" shape contains rectangle");
+      return CONTAINS;
+    }
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof XdYZSolid))
+      return false;
+    XdYZSolid other = (XdYZSolid) o;
+    if (!super.equals(other)) {
+      return false;
+    }
+    return other.minXPlane.equals(minXPlane) &&
+      other.maxXPlane.equals(maxXPlane) &&
+      other.yPlane.equals(yPlane) &&
+      other.minZPlane.equals(minZPlane) &&
+      other.maxZPlane.equals(maxZPlane);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result  + minXPlane.hashCode();
+    result = 31 * result  + maxXPlane.hashCode();
+    result = 31 * result  + yPlane.hashCode();
+    result = 31 * result  + minZPlane.hashCode();
+    result = 31 * result  + maxZPlane.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "XdYZSolid: {planetmodel="+planetModel+", minXplane="+minXPlane+", maxXplane="+maxXPlane+", yplane="+yPlane+", minZplane="+minZPlane+", maxZplane="+maxZPlane+"}";
+  }
+  
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XdYdZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XdYdZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XdYdZSolid.java
new file mode 100644
index 0000000..33d0bea
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XdYdZSolid.java
@@ -0,0 +1,138 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in Y and Z.
+ * This figure, in fact, represents either zero, one, or two points, so the
+ * actual data stored is minimal.
+ *
+ * @lucene.internal
+ */
+public class XdYdZSolid extends BaseXYZSolid {
+
+  /** The points in this figure on the planet surface; also doubles for edge points */
+  protected final GeoPoint[] surfacePoints;
+  
+  /**
+   * Sole constructor
+   *
+   *@param planetModel is the planet model.
+   *@param minX is the minimum X value.
+   *@param maxX is the maximum X value.
+   *@param Y is the Y value.
+   *@param Z is the Z value.
+   */
+  public XdYdZSolid(final PlanetModel planetModel,
+    final double minX,
+    final double maxX,
+    final double Y,
+    final double Z) {
+    super(planetModel);
+    // Argument checking
+    if (maxX - minX < Vector.MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("X values in wrong order or identical");
+
+    // Build the planes and intersect them.
+    final Plane yPlane = new Plane(yUnitVector,-Y);
+    final Plane zPlane = new Plane(zUnitVector,-Z);
+    final SidedPlane minXPlane = new SidedPlane(maxX,0.0,0.0,xUnitVector,-minX);
+    final SidedPlane maxXPlane = new SidedPlane(minX,0.0,0.0,xUnitVector,-maxX);
+    surfacePoints = yPlane.findIntersections(planetModel,zPlane,minXPlane,maxXPlane);
+  }
+
+  @Override
+  protected GeoPoint[] getEdgePoints() {
+    return surfacePoints;
+  }
+  
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    for (final GeoPoint p : surfacePoints) {
+      if (p.isIdentical(x,y,z))
+        return true;
+    }
+    return false;
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    //System.err.println(this+" getrelationship with "+path);
+    final int insideRectangle = isShapeInsideArea(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some inside");
+      return OVERLAPS;
+    }
+
+    // Figure out if the entire XYZArea is contained by the shape.
+    final int insideShape = isAreaInsideShape(path);
+    if (insideShape == SOME_INSIDE) {
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
+      //System.err.println(" inside of each other");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      return WITHIN;
+    }
+    
+    if (insideShape == ALL_INSIDE) {
+      //System.err.println(" shape contains rectangle");
+      return CONTAINS;
+    }
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof XdYdZSolid))
+      return false;
+    XdYdZSolid other = (XdYdZSolid) o;
+    if (!super.equals(other) || surfacePoints.length != other.surfacePoints.length ) {
+      return false;
+    }
+    for (int i = 0; i < surfacePoints.length; i++) {
+      if (!surfacePoints[i].equals(other.surfacePoints[i]))
+        return false;
+    }
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    for (final GeoPoint p : surfacePoints) {
+      result = 31 * result  + p.hashCode();
+    }
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    final StringBuilder sb = new StringBuilder();
+    for (final GeoPoint p : surfacePoints) {
+      sb.append(" ").append(p).append(" ");
+    }
+    return "XdYdZSolid: {planetmodel="+planetModel+", "+sb.toString()+"}";
+  }
+  
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXYZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXYZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXYZSolid.java
new file mode 100644
index 0000000..48fe714
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXYZSolid.java
@@ -0,0 +1,216 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in X.
+ *
+ * @lucene.internal
+ */
+public class dXYZSolid extends BaseXYZSolid {
+
+  /** X plane */
+  protected final Plane xPlane;
+  /** Min-Y plane */
+  protected final SidedPlane minYPlane;
+  /** Max-Y plane */
+  protected final SidedPlane maxYPlane;
+  /** Min-Z plane */
+  protected final SidedPlane minZPlane;
+  /** Max-Z plane */
+  protected final SidedPlane maxZPlane;
+  
+  /** These are the edge points of the shape, which are defined to be at least one point on
+   * each surface area boundary.  In the case of a solid, this includes points which represent
+   * the intersection of XYZ bounding planes and the planet, as well as points representing
+   * the intersection of single bounding planes with the planet itself.
+   */
+  protected final GeoPoint[] edgePoints;
+
+  /** Notable points for XPlane */
+  protected final GeoPoint[] notableXPoints;
+
+  /**
+   * Sole constructor
+   *
+   *@param planetModel is the planet model.
+   *@param X is the X value.
+   *@param minY is the minimum Y value.
+   *@param maxY is the maximum Y value.
+   *@param minZ is the minimum Z value.
+   *@param maxZ is the maximum Z value.
+   */
+  public dXYZSolid(final PlanetModel planetModel,
+    final double X,
+    final double minY,
+    final double maxY,
+    final double minZ,
+    final double maxZ) {
+    super(planetModel);
+    // Argument checking
+    if (maxY - minY < Vector.MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("Y values in wrong order or identical");
+    if (maxZ - minZ < Vector.MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("Z values in wrong order or identical");
+
+    final double worldMinX = planetModel.getMinimumXValue();
+    final double worldMaxX = planetModel.getMaximumXValue();
+    
+    // Construct the planes
+    xPlane = new Plane(xUnitVector,-X);
+    minYPlane = new SidedPlane(0.0,maxY,0.0,yUnitVector,-minY);
+    maxYPlane = new SidedPlane(0.0,minY,0.0,yUnitVector,-maxY);
+    minZPlane = new SidedPlane(0.0,0.0,maxZ,zUnitVector,-minZ);
+    maxZPlane = new SidedPlane(0.0,0.0,minZ,zUnitVector,-maxZ);
+      
+    // We need at least one point on the planet surface for each manifestation of the shape.
+    // There can be up to 2 (on opposite sides of the world).  But we have to go through
+    // 4 combinations of adjacent planes in order to find out if any have 2 intersection solution.
+    // Typically, this requires 4 square root operations. 
+    final GeoPoint[] XminY = xPlane.findIntersections(planetModel,minYPlane,maxYPlane,minZPlane,maxZPlane);
+    final GeoPoint[] XmaxY = xPlane.findIntersections(planetModel,maxYPlane,minYPlane,minZPlane,maxZPlane);
+    final GeoPoint[] XminZ = xPlane.findIntersections(planetModel,minZPlane,maxZPlane,minYPlane,maxYPlane);
+    final GeoPoint[] XmaxZ = xPlane.findIntersections(planetModel,maxZPlane,minZPlane,minYPlane,maxYPlane);
+
+    notableXPoints = glueTogether(XminY, XmaxY, XminZ, XmaxZ);
+
+    // Now, compute the edge points.
+    // This is the trickiest part of setting up an XYZSolid.  We've computed intersections already, so
+    // we'll start there.  We know that at most there will be two disconnected shapes on the planet surface.
+    // But there's also a case where exactly one plane slices through the world, and none of the bounding plane
+    // intersections do.  Thus, if we don't find any of the edge intersection cases, we have to look for that last case.
+      
+    // We need to look at single-plane/world intersections.
+    // We detect these by looking at the world model and noting its x, y, and z bounds.
+    // For the single-dimension degenerate case, there's really only one plane that can possibly intersect the world.
+    // The cases we are looking for are when the four corner points for any given
+    // plane are all outside of the world, AND that plane intersects the world.
+    // There are four corner points all told; we must evaluate these WRT the planet surface.
+    final boolean XminYminZ = planetModel.pointOutside(X, minY, minZ);
+    final boolean XminYmaxZ = planetModel.pointOutside(X, minY, maxZ);
+    final boolean XmaxYminZ = planetModel.pointOutside(X, maxY, minZ);
+    final boolean XmaxYmaxZ = planetModel.pointOutside(X, maxY, maxZ);
+
+    final GeoPoint[] xEdges;
+    if (X - worldMinX >= -Vector.MINIMUM_RESOLUTION && X - worldMaxX <= Vector.MINIMUM_RESOLUTION &&
+      minY < 0.0 && maxY > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
+      XminYminZ && XminYmaxZ && XmaxYminZ && XmaxYmaxZ) {
+      // Find any point on the X plane that intersects the world
+      // First construct a perpendicular plane that will allow us to find a sample point.
+      // This plane is vertical and goes through the points (0,0,0) and (1,0,0)
+      // Then use it to compute a sample point.
+      final GeoPoint intPoint = xPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
+      if (intPoint != null) {
+        xEdges = new GeoPoint[]{intPoint};
+      } else {
+        xEdges = EMPTY_POINTS;
+      }
+    } else {
+      xEdges = EMPTY_POINTS;
+    }
+
+    this.edgePoints = glueTogether(XminY,XmaxY,XminZ,XmaxZ,xEdges);
+  }
+
+  @Override
+  protected GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+  
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return xPlane.evaluateIsZero(x, y, z) &&
+      minYPlane.isWithin(x, y, z) &&
+      maxYPlane.isWithin(x, y, z) &&
+      minZPlane.isWithin(x, y, z) &&
+      maxZPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    //System.err.println(this+" getrelationship with "+path);
+    final int insideRectangle = isShapeInsideArea(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some shape points inside area");
+      return OVERLAPS;
+    }
+
+    // Figure out if the entire XYZArea is contained by the shape.
+    final int insideShape = isAreaInsideShape(path);
+    if (insideShape == SOME_INSIDE) {
+      //System.err.println(" some area points inside shape");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
+      //System.err.println(" inside of each other");
+      return OVERLAPS;
+    }
+
+    // The entire locus of points in this shape is on a single plane, so we only need ot look for an intersection with that plane.
+    //System.err.println("xPlane = "+xPlane);
+    if (path.intersects(xPlane, notableXPoints, minYPlane, maxYPlane, minZPlane, maxZPlane)) {
+      //System.err.println(" edges intersect");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      //System.err.println(" shape points inside area");
+      return WITHIN;
+    }
+
+    if (insideShape == ALL_INSIDE) {
+      //System.err.println(" shape contains all area");
+      return CONTAINS;
+    }
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof dXYZSolid))
+      return false;
+    dXYZSolid other = (dXYZSolid) o;
+    if (!super.equals(other)) {
+      return false;
+    }
+    return other.xPlane.equals(xPlane) &&
+      other.minYPlane.equals(minYPlane) &&
+      other.maxYPlane.equals(maxYPlane) &&
+      other.minZPlane.equals(minZPlane) &&
+      other.maxZPlane.equals(maxZPlane);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result  + xPlane.hashCode();
+    result = 31 * result  + minYPlane.hashCode();
+    result = 31 * result  + maxYPlane.hashCode();
+    result = 31 * result  + minZPlane.hashCode();
+    result = 31 * result  + maxZPlane.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "dXYZSolid: {planetmodel="+planetModel+", xplane="+xPlane+", minYplane="+minYPlane+", maxYplane="+maxYPlane+", minZplane="+minZPlane+", maxZplane="+maxZPlane+"}";
+  }
+  
+}
+  


[03/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 0093e26)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXYdZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXYdZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXYdZSolid.java
new file mode 100644
index 0000000..d824f26
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXYdZSolid.java
@@ -0,0 +1,138 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in X and Z.
+ * This figure, in fact, represents either zero, one, or two points, so the
+ * actual data stored is minimal.
+ *
+ * @lucene.internal
+ */
+public class dXYdZSolid extends BaseXYZSolid {
+
+  /** The points in this figure on the planet surface; also doubles for edge points */
+  protected final GeoPoint[] surfacePoints;
+  
+  /**
+   * Sole constructor
+   *
+   *@param planetModel is the planet model.
+   *@param X is the X value.
+   *@param minY is the minimum Y value.
+   *@param maxY is the maximum Y value.
+   *@param Z is the Z value.
+   */
+  public dXYdZSolid(final PlanetModel planetModel,
+    final double X,
+    final double minY,
+    final double maxY,
+    final double Z) {
+    super(planetModel);
+    // Argument checking
+    if (maxY - minY < Vector.MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("Y values in wrong order or identical");
+
+    // Build the planes and intersect them.
+    final Plane xPlane = new Plane(xUnitVector,-X);
+    final Plane zPlane = new Plane(zUnitVector,-Z);
+    final SidedPlane minYPlane = new SidedPlane(0.0,maxY,0.0,yUnitVector,-minY);
+    final SidedPlane maxYPlane = new SidedPlane(0.0,minY,0.0,yUnitVector,-maxY);
+    surfacePoints = xPlane.findIntersections(planetModel,zPlane,minYPlane,maxYPlane);
+  }
+
+  @Override
+  protected GeoPoint[] getEdgePoints() {
+    return surfacePoints;
+  }
+  
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    for (final GeoPoint p : surfacePoints) {
+      if (p.isIdentical(x,y,z))
+        return true;
+    }
+    return false;
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    //System.err.println(this+" getrelationship with "+path);
+    final int insideRectangle = isShapeInsideArea(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some inside");
+      return OVERLAPS;
+    }
+
+    // Figure out if the entire XYZArea is contained by the shape.
+    final int insideShape = isAreaInsideShape(path);
+    if (insideShape == SOME_INSIDE) {
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
+      //System.err.println(" inside of each other");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      return WITHIN;
+    }
+    
+    if (insideShape == ALL_INSIDE) {
+      //System.err.println(" shape contains rectangle");
+      return CONTAINS;
+    }
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof dXYdZSolid))
+      return false;
+    dXYdZSolid other = (dXYdZSolid) o;
+    if (!super.equals(other) || surfacePoints.length != other.surfacePoints.length ) {
+      return false;
+    }
+    for (int i = 0; i < surfacePoints.length; i++) {
+      if (!surfacePoints[i].equals(other.surfacePoints[i]))
+        return false;
+    }
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    for (final GeoPoint p : surfacePoints) {
+      result = 31 * result  + p.hashCode();
+    }
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    final StringBuilder sb = new StringBuilder();
+    for (final GeoPoint p : surfacePoints) {
+      sb.append(" ").append(p).append(" ");
+    }
+    return "dXYdZSolid: {planetmodel="+planetModel+", "+sb.toString()+"}";
+  }
+  
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXdYZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXdYZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXdYZSolid.java
new file mode 100644
index 0000000..b9942b5
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXdYZSolid.java
@@ -0,0 +1,138 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in X and Y.
+ * This figure, in fact, represents either zero, one, or two points, so the
+ * actual data stored is minimal.
+ *
+ * @lucene.internal
+ */
+public class dXdYZSolid extends BaseXYZSolid {
+
+  /** The points in this figure on the planet surface; also doubles for edge points */
+  protected final GeoPoint[] surfacePoints;
+  
+  /**
+   * Sole constructor
+   *
+   *@param planetModel is the planet model.
+   *@param X is the X value.
+   *@param Y is the Y value.
+   *@param minZ is the minimum Z value.
+   *@param maxZ is the maximum Z value.
+   */
+  public dXdYZSolid(final PlanetModel planetModel,
+    final double X,
+    final double Y,
+    final double minZ,
+    final double maxZ) {
+    super(planetModel);
+    // Argument checking
+    if (maxZ - minZ < Vector.MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("Z values in wrong order or identical");
+
+    // Build the planes and intersect them.
+    final Plane xPlane = new Plane(xUnitVector,-X);
+    final Plane yPlane = new Plane(yUnitVector,-Y);
+    final SidedPlane minZPlane = new SidedPlane(0.0,0.0,maxZ,zUnitVector,-minZ);
+    final SidedPlane maxZPlane = new SidedPlane(0.0,0.0,minZ,zUnitVector,-maxZ);
+    surfacePoints = xPlane.findIntersections(planetModel,yPlane,minZPlane,maxZPlane);
+  }
+
+  @Override
+  protected GeoPoint[] getEdgePoints() {
+    return surfacePoints;
+  }
+  
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    for (final GeoPoint p : surfacePoints) {
+      if (p.isIdentical(x,y,z))
+        return true;
+    }
+    return false;
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    //System.err.println(this+" getrelationship with "+path);
+    final int insideRectangle = isShapeInsideArea(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some inside");
+      return OVERLAPS;
+    }
+
+    // Figure out if the entire XYZArea is contained by the shape.
+    final int insideShape = isAreaInsideShape(path);
+    if (insideShape == SOME_INSIDE) {
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
+      //System.err.println(" inside of each other");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      return WITHIN;
+    }
+    
+    if (insideShape == ALL_INSIDE) {
+      //System.err.println(" shape contains rectangle");
+      return CONTAINS;
+    }
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof dXdYZSolid))
+      return false;
+    dXdYZSolid other = (dXdYZSolid) o;
+    if (!super.equals(other) || surfacePoints.length != other.surfacePoints.length ) {
+      return false;
+    }
+    for (int i = 0; i < surfacePoints.length; i++) {
+      if (!surfacePoints[i].equals(other.surfacePoints[i]))
+        return false;
+    }
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    for (final GeoPoint p : surfacePoints) {
+      result = 31 * result  + p.hashCode();
+    }
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    final StringBuilder sb = new StringBuilder();
+    for (final GeoPoint p : surfacePoints) {
+      sb.append(" ").append(p).append(" ");
+    }
+    return "dXdYZSolid: {planetmodel="+planetModel+", "+sb.toString()+"}";
+  }
+  
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXdYdZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXdYdZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXdYdZSolid.java
new file mode 100644
index 0000000..66dcab8
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXdYdZSolid.java
@@ -0,0 +1,146 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in all dimensions
+ *
+ * @lucene.internal
+ */
+public class dXdYdZSolid extends BaseXYZSolid {
+
+  /** On surface? */
+  protected final boolean isOnSurface;
+  /** The point */
+  protected final GeoPoint thePoint;
+  
+  /** These are the edge points of the shape, which are defined to be at least one point on
+   * each surface area boundary.  In the case of a solid, this includes points which represent
+   * the intersection of XYZ bounding planes and the planet, as well as points representing
+   * the intersection of single bounding planes with the planet itself.
+   */
+  protected final GeoPoint[] edgePoints;
+
+  /** Empty array of {@link GeoPoint}. */
+  protected static final GeoPoint[] nullPoints = new GeoPoint[0];
+  
+  /**
+   * Sole constructor
+   *
+   *@param planetModel is the planet model.
+   *@param X is the X value.
+   *@param Y is the Y value.
+   *@param Z is the Z value.
+   */
+  public dXdYdZSolid(final PlanetModel planetModel,
+    final double X,
+    final double Y,
+    final double Z) {
+    super(planetModel);
+    isOnSurface = planetModel.pointOnSurface(X,Y,Z);
+    if (isOnSurface) {
+      thePoint = new GeoPoint(X,Y,Z);
+      edgePoints = new GeoPoint[]{thePoint};
+    } else {
+      thePoint = null;
+      edgePoints = nullPoints;
+    }
+  }
+
+  @Override
+  protected GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+  
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    if (!isOnSurface) {
+      return false;
+    }
+    return thePoint.isIdentical(x,y,z);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    if (!isOnSurface) {
+      return DISJOINT;
+    }
+    
+    //System.err.println(this+" getrelationship with "+path);
+    final int insideRectangle = isShapeInsideArea(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some shape points inside area");
+      return OVERLAPS;
+    }
+
+    // Figure out if the entire XYZArea is contained by the shape.
+    final int insideShape = isAreaInsideShape(path);
+    if (insideShape == SOME_INSIDE) {
+      //System.err.println(" some area points inside shape");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
+      //System.err.println(" inside of each other");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      //System.err.println(" shape inside area entirely");
+      return WITHIN;
+    }
+
+    if (insideShape == ALL_INSIDE) {
+      //System.err.println(" shape contains area entirely");
+      return CONTAINS;
+    }
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof dXdYdZSolid))
+      return false;
+    dXdYdZSolid other = (dXdYdZSolid) o;
+    if (!super.equals(other) ||
+      other.isOnSurface != isOnSurface) {
+      return false;
+    }
+    if (isOnSurface) {
+      return other.thePoint.equals(thePoint);
+    }
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + (isOnSurface?1:0);
+    if (isOnSurface) {
+      result = 31 * result  + thePoint.hashCode();
+    }
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "dXdYdZSolid: {planetmodel="+planetModel+", isOnSurface="+isOnSurface+", thePoint="+thePoint+"}";
+  }
+  
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/package-info.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/package-info.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/package-info.java
new file mode 100644
index 0000000..446365c
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/**
+ * Shapes implemented using 3D planar geometry.  This package has no dependencies aside from Java.
+ * This code was contributed under the name "Geo3D".
+ */
+package org.apache.lucene.spatial3d.geom;

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/package-info.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/package-info.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/package-info.java
new file mode 100644
index 0000000..032d26f
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+/**
+ * Lucene field &amp; query support for the spatial geometry implemented in {@link org.apache.lucene.spatial3d.geom}.
+ */
+package org.apache.lucene.spatial3d;

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/overview.html
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/overview.html b/lucene/spatial3d/src/java/overview.html
index 152d06e..293cc65a 100644
--- a/lucene/spatial3d/src/java/overview.html
+++ b/lucene/spatial3d/src/java/overview.html
@@ -23,7 +23,8 @@
   <h1>The Spatial3D Module for Apache Lucene</h1>
 
   <p>
-    APIs for planar spatial3d math.
+    APIs for planar spatial3d math.  It is mostly comprised of computational geometry code in the
+    "org.apache.lucene.spatial3d.geom" package (AKA "Geo3D").
   </p>
   </body>
 </html>

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoBBoxTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoBBoxTest.java b/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoBBoxTest.java
deleted file mode 100755
index b76134e..0000000
--- a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoBBoxTest.java
+++ /dev/null
@@ -1,364 +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.geo3d;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-public class GeoBBoxTest {
-
-  protected final double DEGREES_TO_RADIANS = Math.PI / 180.0;
-
-  @Test
-  public void testBBoxDegenerate() {
-    GeoBBox box;
-    GeoConvexPolygon cp;
-    int relationship;
-    List<GeoPoint> points = new ArrayList<GeoPoint>();
-    points.add(new GeoPoint(PlanetModel.SPHERE, 24 * DEGREES_TO_RADIANS, -30 * DEGREES_TO_RADIANS));
-    points.add(new GeoPoint(PlanetModel.SPHERE, -11 * DEGREES_TO_RADIANS, 101 * DEGREES_TO_RADIANS));
-    points.add(new GeoPoint(PlanetModel.SPHERE, -49 * DEGREES_TO_RADIANS, -176 * DEGREES_TO_RADIANS));
-    GeoMembershipShape shape = GeoPolygonFactory.makeGeoPolygon(PlanetModel.SPHERE, points, 0);
-    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, -64 * DEGREES_TO_RADIANS, -64 * DEGREES_TO_RADIANS, -180 * DEGREES_TO_RADIANS, 180 * DEGREES_TO_RADIANS);
-    relationship = box.getRelationship(shape);
-    assertEquals(GeoArea.CONTAINS, relationship);
-    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, -61.85 * DEGREES_TO_RADIANS, -67.5 * DEGREES_TO_RADIANS, -180 * DEGREES_TO_RADIANS, -168.75 * DEGREES_TO_RADIANS);
-    //System.out.println("Shape = " + shape + " Rect = " + box);
-    relationship = box.getRelationship(shape);
-    assertEquals(GeoArea.CONTAINS, relationship);
-  }
-
-  @Test
-  public void testBBoxPointWithin() {
-    GeoBBox box;
-    GeoPoint gp;
-
-    // Standard normal Rect box, not crossing dateline
-    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, -1.0, 1.0);
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, 0.0);
-    assertTrue(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.1, 0.0);
-    assertFalse(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0);
-    assertFalse(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, 1.1);
-    assertFalse(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -1.1);
-    assertFalse(box.isWithin(gp));
-    assertEquals(0.1,box.computeOutsideDistance(DistanceStyle.ARC,gp),1e-2);
-    assertEquals(0.1,box.computeOutsideDistance(DistanceStyle.NORMAL,gp),1e-2);
-    assertEquals(0.1,box.computeOutsideDistance(DistanceStyle.NORMAL,gp),1e-2);
-
-    // Standard normal Rect box, crossing dateline
-    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, Math.PI - 1.0, -Math.PI + 1.0);
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -Math.PI);
-    assertTrue(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.1, -Math.PI);
-    assertFalse(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.5, -Math.PI);
-    assertFalse(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -Math.PI + 1.1);
-    assertFalse(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, (-Math.PI - 1.1) + Math.PI * 2.0);
-    assertFalse(box.isWithin(gp));
-
-    // Latitude zone rectangle
-    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, -Math.PI, Math.PI);
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -Math.PI);
-    assertTrue(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.1, -Math.PI);
-    assertFalse(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.5, -Math.PI);
-    assertFalse(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -Math.PI + 1.1);
-    assertTrue(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, (-Math.PI - 1.1) + Math.PI * 2.0);
-    assertTrue(box.isWithin(gp));
-
-    // World
-    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, -Math.PI, Math.PI);
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -Math.PI);
-    assertTrue(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.1, -Math.PI);
-    assertTrue(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.5, -Math.PI);
-    assertTrue(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -Math.PI + 1.1);
-    assertTrue(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, (-Math.PI - 1.1) + Math.PI * 2.0);
-    assertTrue(box.isWithin(gp));
-
-  }
-
-  @Test
-  public void testBBoxExpand() {
-    GeoBBox box;
-    GeoPoint gp;
-    // Standard normal Rect box, not crossing dateline
-    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, -1.0, 1.0);
-    box = box.expand(0.1);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, 0.0);
-    assertTrue(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.15, 0.0);
-    assertFalse(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.25 - 0.05, 0.0);
-    assertTrue(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.25 - 0.15, 0.0);
-    assertFalse(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -1.05);
-    assertTrue(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -1.15);
-    assertFalse(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, 1.05);
-    assertTrue(box.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, 1.15);
-    assertFalse(box.isWithin(gp));
-  }
-
-  @Test
-  public void testBBoxBounds() {
-    GeoBBox c;
-    LatLonBounds b;
-    XYZBounds xyzb;
-    GeoArea solid;
-    GeoPoint point;
-    int relationship;
-    
-    c= GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.7570958596622309, -0.7458670829264561, -0.9566079379002148, 1.4802570961901191);
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE,0.10922258701604912,0.1248184603754517,-0.8172414690802067,0.9959041483215542,-0.6136586624726926,0.6821740363641521);
-    point = new GeoPoint(PlanetModel.SPHERE, 0.3719987557178081, 1.4529582778845198);
-    assertTrue(c.isWithin(point));
-    assertTrue(solid.isWithin(point));
-    relationship = solid.getRelationship(c);
-    assertTrue(relationship == GeoArea.OVERLAPS || relationship == GeoArea.CONTAINS || relationship == GeoArea.WITHIN);
-
-    c= GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.006607096847842122, -0.002828135860810422, -0.0012934461873348349, 0.006727418645092394);
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE,0.9999995988328008,1.0000000002328306,-0.0012934708508166816,0.006727393021214471,-0.002828157275369464,0.006607074060760007);
-    point = new GeoPoint(PlanetModel.SPHERE, -5.236470872437899E-4, 3.992578692654256E-4);
-    assertTrue(c.isWithin(point));
-    assertTrue(solid.isWithin(point));
-    relationship = solid.getRelationship(c);
-    assertTrue(relationship == GeoArea.OVERLAPS || relationship == GeoArea.CONTAINS || relationship == GeoArea.WITHIN);
-    
-    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.25, -Math.PI * 0.25, -1.0, 1.0);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(-1.0, b.getLeftLongitude(), 0.000001);
-    assertEquals(1.0, b.getRightLongitude(), 0.000001);
-    assertEquals(-Math.PI * 0.25, b.getMinLatitude(), 0.000001);
-    assertEquals(Math.PI * 0.25, b.getMaxLatitude(), 0.000001);
-    assertEquals(0.382051, xyzb.getMinimumX(), 0.000001);
-    assertEquals(1.0, xyzb.getMaximumX(), 0.000001);
-    assertEquals(-0.841471, xyzb.getMinimumY(), 0.000001);
-    assertEquals(0.841471, xyzb.getMaximumY(), 0.000001);
-    assertEquals(-0.707107, xyzb.getMinimumZ(), 0.000001);
-    assertEquals(0.707107, xyzb.getMaximumZ(), 0.000001);
-    
-    GeoArea area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE,
-      xyzb.getMinimumX() - 2.0 * Vector.MINIMUM_RESOLUTION,
-      xyzb.getMaximumX() + 2.0 * Vector.MINIMUM_RESOLUTION,
-      xyzb.getMinimumY() - 2.0 * Vector.MINIMUM_RESOLUTION,
-      xyzb.getMaximumY() + 2.0 * Vector.MINIMUM_RESOLUTION,
-      xyzb.getMinimumZ() - 2.0 * Vector.MINIMUM_RESOLUTION,
-      xyzb.getMaximumZ() + 2.0 * Vector.MINIMUM_RESOLUTION);
-    assertEquals(GeoArea.WITHIN, area.getRelationship(c));
-
-    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, -1.0, 1.0);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(-1.0, b.getLeftLongitude(), 0.000001);
-    assertEquals(1.0, b.getRightLongitude(), 0.000001);
-    assertEquals(-Math.PI * 0.25, b.getMinLatitude(), 0.000001);
-    assertEquals(0.0, b.getMaxLatitude(), 0.000001);
-    assertEquals(0.382051, xyzb.getMinimumX(), 0.000001);
-    assertEquals(1.0, xyzb.getMaximumX(), 0.000001);
-    assertEquals(-0.841471, xyzb.getMinimumY(), 0.000001);
-    assertEquals(0.841471, xyzb.getMaximumY(), 0.000001);
-    assertEquals(-0.707107, xyzb.getMinimumZ(), 0.000001);
-    assertEquals(0.0, xyzb.getMaximumZ(), 0.000001);
-
-    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, 1.0, -1.0);
-
-    b = new LatLonBounds();
-    c.getBounds(b);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    assertTrue(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    //assertEquals(1.0,b.getLeftLongitude(),0.000001);
-    //assertEquals(-1.0,b.getRightLongitude(),0.000001);
-    assertEquals(-Math.PI * 0.25, b.getMinLatitude(), 0.000001);
-    assertEquals(0.0, b.getMaxLatitude(), 0.000001);
-    assertEquals(-1.0, xyzb.getMinimumX(), 0.000001);
-    assertEquals(0.540303, xyzb.getMaximumX(), 0.000001);
-    assertEquals(-1.0, xyzb.getMinimumY(), 0.000001);
-    assertEquals(1.0, xyzb.getMaximumY(), 0.000001);
-    assertEquals(-0.707107, xyzb.getMinimumZ(), 0.000001);
-    assertEquals(0.0, xyzb.getMaximumZ(), 0.000001);
-
-
-    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, -1.0, 1.0);
-
-    b = new LatLonBounds();
-    c.getBounds(b);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    assertTrue(b.checkNoLongitudeBound());
-    assertTrue(b.checkNoTopLatitudeBound());
-    assertTrue(b.checkNoBottomLatitudeBound());
-    //assertEquals(-1.0, b.getLeftLongitude(), 0.000001);
-    //assertEquals(1.0, b.getRightLongitude(), 0.000001);
-    assertEquals(0.0, xyzb.getMinimumX(), 0.000001);
-    assertEquals(1.0, xyzb.getMaximumX(), 0.000001);
-    assertEquals(-0.841471, xyzb.getMinimumY(), 0.000001);
-    assertEquals(0.841471, xyzb.getMaximumY(), 0.000001);
-    assertEquals(-1.0, xyzb.getMinimumZ(), 0.000001);
-    assertEquals(1.0, xyzb.getMaximumZ(), 0.000001);
-
-    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, 1.0, -1.0);
-
-    b = new LatLonBounds();
-    c.getBounds(b);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    assertTrue(b.checkNoLongitudeBound());
-    assertTrue(b.checkNoTopLatitudeBound());
-    assertTrue(b.checkNoBottomLatitudeBound());
-    //assertEquals(1.0,b.getLeftLongitude(),0.000001);
-    //assertEquals(-1.0,b.getRightLongitude(),0.000001);
-    assertEquals(-1.0, xyzb.getMinimumX(), 0.000001);
-    assertEquals(0.540303, xyzb.getMaximumX(), 0.000001);
-    assertEquals(-1.0, xyzb.getMinimumY(), 0.000001);
-    assertEquals(1.0, xyzb.getMaximumY(), 0.000001);
-    assertEquals(-1.0, xyzb.getMinimumZ(), 0.000001);
-    assertEquals(1.0, xyzb.getMaximumZ(), 0.000001);
-
-    // Check wide variants of rectangle and longitude slice
-
-    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, -Math.PI + 0.1, Math.PI - 0.1);
-
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertTrue(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    //assertEquals(-Math.PI+0.1,b.getLeftLongitude(),0.000001);
-    //assertEquals(Math.PI-0.1,b.getRightLongitude(),0.000001);
-    assertEquals(-Math.PI * 0.25, b.getMinLatitude(), 0.000001);
-    assertEquals(0.0, b.getMaxLatitude(), 0.000001);
-
-    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, Math.PI - 0.1, -Math.PI + 0.1);
-
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(Math.PI - 0.1, b.getLeftLongitude(), 0.000001);
-    assertEquals(-Math.PI + 0.1, b.getRightLongitude(), 0.000001);
-    assertEquals(-Math.PI * 0.25, b.getMinLatitude(), 0.000001);
-    assertEquals(0.0, b.getMaxLatitude(), 0.000001);
-
-    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, -Math.PI + 0.1, Math.PI - 0.1);
-
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertTrue(b.checkNoLongitudeBound());
-    assertTrue(b.checkNoTopLatitudeBound());
-    assertTrue(b.checkNoBottomLatitudeBound());
-    //assertEquals(-Math.PI+0.1,b.getLeftLongitude(),0.000001);
-    //assertEquals(Math.PI-0.1,b.getRightLongitude(),0.000001);
-
-    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, Math.PI - 0.1, -Math.PI + 0.1);
-
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertTrue(b.checkNoLongitudeBound());
-    assertTrue(b.checkNoTopLatitudeBound());
-    assertTrue(b.checkNoBottomLatitudeBound());
-    //assertEquals(Math.PI - 0.1, b.getLeftLongitude(), 0.000001);
-    //assertEquals(-Math.PI + 0.1, b.getRightLongitude(), 0.000001);
-
-    // Check latitude zone
-    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 1.0, -1.0, -Math.PI, Math.PI);
-
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertTrue(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(-1.0, b.getMinLatitude(), 0.000001);
-    assertEquals(1.0, b.getMaxLatitude(), 0.000001);
-
-    // Now, combine a few things to test the bounds object
-    GeoBBox c1;
-    GeoBBox c2;
-
-    c1 = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, -Math.PI, 0.0);
-    c2 = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, 0.0, Math.PI);
-
-    b = new LatLonBounds();
-    c1.getBounds(b);
-    c2.getBounds(b);
-    assertTrue(b.checkNoLongitudeBound());
-    assertTrue(b.checkNoTopLatitudeBound());
-    assertTrue(b.checkNoBottomLatitudeBound());
-
-    c1 = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, -Math.PI, 0.0);
-    c2 = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, 0.0, Math.PI * 0.5);
-
-    b = new LatLonBounds();
-    c1.getBounds(b);
-    c2.getBounds(b);
-    assertTrue(b.checkNoLongitudeBound());
-    assertTrue(b.checkNoTopLatitudeBound());
-    assertTrue(b.checkNoBottomLatitudeBound());
-    //assertEquals(-Math.PI,b.getLeftLongitude(),0.000001);
-    //assertEquals(Math.PI*0.5,b.getRightLongitude(),0.000001);
-
-    c1 = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, -Math.PI * 0.5, 0.0);
-    c2 = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, 0.0, Math.PI);
-
-    b = new LatLonBounds();
-    c1.getBounds(b);
-    c2.getBounds(b);
-    assertTrue(b.checkNoLongitudeBound());
-    assertTrue(b.checkNoTopLatitudeBound());
-    assertTrue(b.checkNoBottomLatitudeBound());
-    //assertEquals(-Math.PI * 0.5,b.getLeftLongitude(),0.000001);
-    //assertEquals(Math.PI,b.getRightLongitude(),0.000001);
-
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoCircleTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoCircleTest.java b/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoCircleTest.java
deleted file mode 100755
index aa5c2e3..0000000
--- a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoCircleTest.java
+++ /dev/null
@@ -1,415 +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.geo3d;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import org.apache.lucene.util.LuceneTestCase;
-
-public class GeoCircleTest extends LuceneTestCase {
-
-  @Test
-  public void testCircleDistance() {
-    GeoCircle c;
-    GeoPoint gp;
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, -0.5, 0.1);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
-    assertEquals(Double.MAX_VALUE, c.computeDistance(DistanceStyle.ARC,gp), 0.0);
-    assertEquals(Double.MAX_VALUE, c.computeDistance(DistanceStyle.NORMAL,gp), 0.0);
-    assertEquals(Double.MAX_VALUE, c.computeDistance(DistanceStyle.NORMAL,gp), 0.0);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
-    assertEquals(0.0, c.computeDistance(DistanceStyle.ARC,gp), 0.000001);
-    assertEquals(0.0, c.computeDistance(DistanceStyle.NORMAL,gp), 0.000001);
-    assertEquals(0.0, c.computeDistance(DistanceStyle.NORMAL,gp), 0.000001);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, -0.5);
-    assertEquals(0.05, c.computeDistance(DistanceStyle.ARC,gp), 0.000001);
-    assertEquals(0.049995, c.computeDistance(DistanceStyle.LINEAR,gp), 0.000001);
-    assertEquals(0.049979, c.computeDistance(DistanceStyle.NORMAL,gp), 0.000001);
-  }
-
-  @Test
-  public void testCircleFullWorld() {
-    GeoCircle c;
-    GeoPoint gp;
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, -0.5, Math.PI);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.55);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.45);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.5, 0.0);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
-    assertTrue(c.isWithin(gp));
-    LatLonBounds b = new LatLonBounds();
-    c.getBounds(b);
-    assertTrue(b.checkNoLongitudeBound());
-    assertTrue(b.checkNoTopLatitudeBound());
-    assertTrue(b.checkNoBottomLatitudeBound());
-  }
-
-  @Test
-  public void testCirclePointWithin() {
-    GeoCircle c;
-    GeoPoint gp;
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, -0.5, 0.1);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
-    assertFalse(c.isWithin(gp));
-    assertEquals(0.4,c.computeOutsideDistance(DistanceStyle.ARC,gp),1e-12);
-    assertEquals(0.12,c.computeOutsideDistance(DistanceStyle.NORMAL,gp),0.01);
-    assertEquals(0.4,c.computeOutsideDistance(DistanceStyle.LINEAR,gp),0.01);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.55);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.45);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.5, 0.0);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
-    assertFalse(c.isWithin(gp));
-  }
-
-  @Test
-  public void testCircleBounds() {
-    GeoCircle c;
-    LatLonBounds b;
-    XYZBounds xyzb;
-    GeoArea area;
-    GeoPoint p1;
-    GeoPoint p2;
-    int relationship;
-
-    // ...
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84, -0.005931145568901605, -0.001942031539653079, 1.2991918568260272E-4);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84, 1.001098377143621, 1.001100011578687, -0.00207467080358696, -0.0018136665346280983, -0.006067808248760161, -0.005807683665759485);
-    p1 = new GeoPoint(PlanetModel.WGS84, -0.00591253844632244, -0.0020069187259065093);
-    p2 = new GeoPoint(1.001099185736782, -0.0020091272069679327, -0.005919118245803968);
-    assertTrue(c.isWithin(p1));
-    assertTrue(area.isWithin(p1));
-    relationship = area.getRelationship(c);
-    assertTrue(relationship != GeoArea.DISJOINT);
-
-    // Twelfth BKD discovered failure
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84,-0.00824379317765984,-0.0011677469001838581,0.0011530035396910402);
-    p1 = new GeoPoint(PlanetModel.WGS84,-0.006505092992723671,0.007654282718327381);
-    p2 = new GeoPoint(1.0010681673665647,0.007662608264336381,-0.006512324005914593);
-    assertTrue(!c.isWithin(p1));
-    assertTrue(!c.isWithin(p2));
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84, 
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    relationship = area.getRelationship(c);
-    assertTrue(relationship == GeoArea.OVERLAPS || relationship == GeoArea.WITHIN);
-    // Point is actually outside the bounds, and outside the shape
-    assertTrue(!area.isWithin(p1));
-    // Approximate point the same
-    assertTrue(!area.isWithin(p2));
-    
-    // Eleventh BKD discovered failure
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE,-0.004431288600558495,-0.003687846671278374,1.704543429364245E-8);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    //System.err.println(area);
-    relationship = area.getRelationship(c);
-    assertTrue(GeoArea.WITHIN == relationship || GeoArea.OVERLAPS == relationship);
-
-    // Tenth BKD discovered failure
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84,-0.0018829770647349636,-0.001969499061382591,1.3045439293158305E-5);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84, 
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    //System.err.println(area);
-    relationship = area.getRelationship(c);
-    assertTrue(GeoArea.WITHIN == relationship || GeoArea.OVERLAPS == relationship);
-
-    // Ninth BKD discovered failure
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE,-4.211990380885122E-5,-0.0022958453508173044,1.4318475623498535E-5);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    //System.err.println(area);
-    relationship = area.getRelationship(c);
-    assertTrue(GeoArea.WITHIN == relationship || GeoArea.OVERLAPS == relationship);
-    
-    // Eighth BKD discovered failure
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE,0.005321278689117842,-0.00216937368755372,1.5306034422500785E-4);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    //System.err.println(area);
-    relationship = area.getRelationship(c);
-    assertTrue(GeoArea.WITHIN == relationship || GeoArea.OVERLAPS == relationship);
-
-    // Seventh BKD discovered failure
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE,-0.0021627146783861745, -0.0017298167021592304,2.0818312293195752E-4);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    //System.err.println(area);
-    relationship = area.getRelationship(c);
-    assertTrue(GeoArea.WITHIN == relationship || GeoArea.OVERLAPS == relationship);
-
-    // Sixth BKD discovered failure
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84,-0.006450320645814321,0.004660694205115142,0.00489710732634323);
-    //xyzb = new XYZBounds();
-    //c.getBounds(xyzb);
-    //System.err.println("xmin="+xyzb.getMinimumX()+", xmax="+xyzb.getMaximumX()+",ymin="+xyzb.getMinimumY()+", ymax="+xyzb.getMaximumY()+",zmin="+xyzb.getMinimumZ()+", zmax="+xyzb.getMaximumZ());
-    //xmin=1.0010356621420726, xmax=1.0011141249179447,ymin=-2.5326643901354566E-4, ymax=0.009584741915757169,zmin=-0.011359874956269283, zmax=-0.0015549504447452225
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84,1.0010822580620098,1.0010945779732867,0.007079167343247293,0.007541006774427837,-0.0021855011220022575,-0.001896122718181518);
-    assertTrue(GeoArea.CONTAINS != area.getRelationship(c));
-    /*
-    p1 = new GeoPoint(1.0010893045436076,0.007380935180644008,-0.002140671370616495);
-    // This has a different bounding box, so we can't use it.
-    //p2 = new GeoPoint(PlanetModel.WGS84,-0.002164069780096702, 0.007505617500830066);
-    p2 = new GeoPoint(PlanetModel.WGS84,p1.getLatitude(),p1.getLongitude());
-    assertTrue(PlanetModel.WGS84.pointOnSurface(p2));
-    assertTrue(!c.isWithin(p2));
-    assertTrue(!area.isWithin(p2));
-    assertTrue(!c.isWithin(p1));
-    assertTrue(PlanetModel.WGS84.pointOnSurface(p1)); // This fails
-    assertTrue(!area.isWithin(p1)); // This fails
-    */
-    
-    // Fifth BKD discovered failure
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -0.004282454525970269, -1.6739831367422277E-4, 1.959639723134033E-6);
-    assertTrue(c.isWithin(c.getEdgePoints()[0]));
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE,
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    assertTrue(GeoArea.WITHIN == area.getRelationship(c) || GeoArea.OVERLAPS == area.getRelationship(c));
-    
-    // Fourth BKD discovered failure
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -0.0048795517261255, 0.004053904306995974, 5.93699764258874E-6);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE,
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    assertTrue(GeoArea.WITHIN == area.getRelationship(c) || GeoArea.OVERLAPS == area.getRelationship(c));
-    
-    // Yet another test case from BKD
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84, 0.006229478708446979, 0.005570196723795424, 3.840276763694387E-5);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84,
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    p1 = new GeoPoint(PlanetModel.WGS84, 0.006224927111830945, 0.005597367237251763);
-    p2 = new GeoPoint(1.0010836083810235, 0.005603490759433942, 0.006231850560862502);
-    assertTrue(PlanetModel.WGS84.pointOnSurface(p1));
-    //assertTrue(PlanetModel.WGS84.pointOnSurface(p2));
-    assertTrue(c.isWithin(p1));
-    assertTrue(c.isWithin(p2));
-    assertTrue(area.isWithin(p1));
-    assertTrue(area.isWithin(p2));
-    
-    // Another test case from BKD
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -0.005955031040627789, -0.0029274772647399153, 1.601488279374338E-5);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE,
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    
-    relationship = area.getRelationship(c);
-    assertTrue(relationship == GeoArea.WITHIN || relationship == GeoArea.OVERLAPS);
-    
-    // Test case from BKD
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -0.765816119338, 0.991848766844, 0.8153163226330487);
-    p1 = new GeoPoint(0.7692262265236023, -0.055089298115534646, -0.6365973465711254);
-    assertTrue(c.isWithin(p1));
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    assertTrue(p1.x >= xyzb.getMinimumX() && p1.x <= xyzb.getMaximumX());
-    assertTrue(p1.y >= xyzb.getMinimumY() && p1.y <= xyzb.getMaximumY());
-    assertTrue(p1.z >= xyzb.getMinimumZ() && p1.z <= xyzb.getMaximumZ());
-    
-    // Vertical circle cases
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, -0.5, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(-0.6, b.getLeftLongitude(), 0.000001);
-    assertEquals(-0.4, b.getRightLongitude(), 0.000001);
-    assertEquals(-0.1, b.getMinLatitude(), 0.000001);
-    assertEquals(0.1, b.getMaxLatitude(), 0.000001);
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, 0.5, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(0.4, b.getLeftLongitude(), 0.000001);
-    assertEquals(0.6, b.getRightLongitude(), 0.000001);
-    assertEquals(-0.1, b.getMinLatitude(), 0.000001);
-    assertEquals(0.1, b.getMaxLatitude(), 0.000001);
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(-0.1, b.getLeftLongitude(), 0.000001);
-    assertEquals(0.1, b.getRightLongitude(), 0.000001);
-    assertEquals(-0.1, b.getMinLatitude(), 0.000001);
-    assertEquals(0.1, b.getMaxLatitude(), 0.000001);
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, Math.PI, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(Math.PI - 0.1, b.getLeftLongitude(), 0.000001);
-    assertEquals(-Math.PI + 0.1, b.getRightLongitude(), 0.000001);
-    assertEquals(-0.1, b.getMinLatitude(), 0.000001);
-    assertEquals(0.1, b.getMaxLatitude(), 0.000001);
-    // Horizontal circle cases
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, Math.PI * 0.5, 0.0, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertTrue(b.checkNoLongitudeBound());
-    assertTrue(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(Math.PI * 0.5 - 0.1, b.getMinLatitude(), 0.000001);
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertTrue(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertTrue(b.checkNoBottomLatitudeBound());
-    assertEquals(-Math.PI * 0.5 + 0.1, b.getMaxLatitude(), 0.000001);
-
-    // Now do a somewhat tilted plane, facing different directions.
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, 0.0, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
-    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
-    assertEquals(-0.1, b.getLeftLongitude(), 0.00001);
-    assertEquals(0.1, b.getRightLongitude(), 0.00001);
-
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, Math.PI, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
-    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
-    assertEquals(Math.PI - 0.1, b.getLeftLongitude(), 0.00001);
-    assertEquals(-Math.PI + 0.1, b.getRightLongitude(), 0.00001);
-
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, Math.PI * 0.5, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
-    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
-    assertEquals(Math.PI * 0.5 - 0.1, b.getLeftLongitude(), 0.00001);
-    assertEquals(Math.PI * 0.5 + 0.1, b.getRightLongitude(), 0.00001);
-
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, -Math.PI * 0.5, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
-    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
-    assertEquals(-Math.PI * 0.5 - 0.1, b.getLeftLongitude(), 0.00001);
-    assertEquals(-Math.PI * 0.5 + 0.1, b.getRightLongitude(), 0.00001);
-
-    // Slightly tilted, PI/4 direction.
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, Math.PI * 0.25, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
-    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
-    assertEquals(Math.PI * 0.25 - 0.1, b.getLeftLongitude(), 0.00001);
-    assertEquals(Math.PI * 0.25 + 0.1, b.getRightLongitude(), 0.00001);
-
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, -Math.PI * 0.25, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
-    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
-    assertEquals(-Math.PI * 0.25 - 0.1, b.getLeftLongitude(), 0.00001);
-    assertEquals(-Math.PI * 0.25 + 0.1, b.getRightLongitude(), 0.00001);
-
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -0.01, Math.PI * 0.25, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(0.09, b.getMaxLatitude(), 0.000001);
-    assertEquals(-0.11, b.getMinLatitude(), 0.000001);
-    assertEquals(Math.PI * 0.25 - 0.1, b.getLeftLongitude(), 0.00001);
-    assertEquals(Math.PI * 0.25 + 0.1, b.getRightLongitude(), 0.00001);
-
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -0.01, -Math.PI * 0.25, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(0.09, b.getMaxLatitude(), 0.000001);
-    assertEquals(-0.11, b.getMinLatitude(), 0.000001);
-    assertEquals(-Math.PI * 0.25 - 0.1, b.getLeftLongitude(), 0.00001);
-    assertEquals(-Math.PI * 0.25 + 0.1, b.getRightLongitude(), 0.00001);
-
-    // Now do a somewhat tilted plane.
-    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, -0.5, 0.1);
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
-    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
-    assertEquals(-0.6, b.getLeftLongitude(), 0.00001);
-    assertEquals(-0.4, b.getRightLongitude(), 0.00001);
-
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoConvexPolygonTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoConvexPolygonTest.java b/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoConvexPolygonTest.java
deleted file mode 100755
index d6ca7ba..0000000
--- a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoConvexPolygonTest.java
+++ /dev/null
@@ -1,91 +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.geo3d;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-public class GeoConvexPolygonTest {
-
-
-  @Test
-  public void testPolygonPointWithin() {
-    GeoConvexPolygon c;
-    GeoPoint gp;
-    c = new GeoConvexPolygon(PlanetModel.SPHERE, -0.1, -0.5);
-    c.addPoint(0.0, -0.6, false);
-    c.addPoint(0.1, -0.5, false);
-    c.addPoint(0.0, -0.4, false);
-    c.done(false);
-    // Sample some points within
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.55);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.45);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.05, -0.5);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, -0.5);
-    assertTrue(c.isWithin(gp));
-    // Sample some nearby points outside, and compute distance-to-shape for them as well
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.65);
-    assertFalse(c.isWithin(gp));
-    assertEquals(0.05,c.computeOutsideDistance(DistanceStyle.ARC,gp),1e-12);
-    assertEquals(0.05,c.computeOutsideDistance(DistanceStyle.NORMAL,gp),1e-3);
-    assertEquals(0.05,c.computeOutsideDistance(DistanceStyle.LINEAR,gp),1e-3);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.35);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.15, -0.5);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.15, -0.5);
-    assertFalse(c.isWithin(gp));
-    // Random points outside
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.5, 0.0);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
-    assertFalse(c.isWithin(gp));
-  }
-
-  @Test
-  public void testPolygonBounds() {
-    GeoConvexPolygon c;
-    LatLonBounds b;
-
-    c = new GeoConvexPolygon(PlanetModel.SPHERE, -0.1, -0.5);
-    c.addPoint(0.0, -0.6, false);
-    c.addPoint(0.1, -0.5, false);
-    c.addPoint(0.0, -0.4, false);
-    c.done(false);
-
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(-0.6, b.getLeftLongitude(), 0.000001);
-    assertEquals(-0.4, b.getRightLongitude(), 0.000001);
-    assertEquals(-0.1, b.getMinLatitude(), 0.000001);
-    assertEquals(0.1, b.getMaxLatitude(), 0.000001);
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoModelTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoModelTest.java b/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoModelTest.java
deleted file mode 100644
index b3001d4..0000000
--- a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoModelTest.java
+++ /dev/null
@@ -1,110 +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.geo3d;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-/**
- * Test basic plane functionality.
- */
-public class GeoModelTest {
-
-  protected final static PlanetModel scaledModel = new PlanetModel(1.2,1.5);
-  
-  @Test
-  public void testBasicCircle() {
-    // The point of this test is just to make sure nothing blows up doing normal things with a quite non-spherical model
-    // Make sure that the north pole is in the circle, and south pole isn't
-    final GeoPoint northPole = new GeoPoint(scaledModel, Math.PI * 0.5, 0.0);
-    final GeoPoint southPole = new GeoPoint(scaledModel, -Math.PI * 0.5, 0.0);
-    final GeoPoint point1 = new GeoPoint(scaledModel, Math.PI * 0.25, 0.0);
-    final GeoPoint point2 = new GeoPoint(scaledModel, Math.PI * 0.125, 0.0);
-    
-    GeoCircle circle = new GeoStandardCircle(scaledModel, Math.PI * 0.5, 0.0, 0.01);
-    assertTrue(circle.isWithin(northPole));
-    assertFalse(circle.isWithin(southPole));
-    assertFalse(circle.isWithin(point1));
-    LatLonBounds bounds;
-    bounds = new LatLonBounds();
-    circle.getBounds(bounds);
-    assertTrue(bounds.checkNoLongitudeBound());
-    assertTrue(bounds.checkNoTopLatitudeBound());
-    assertFalse(bounds.checkNoBottomLatitudeBound());
-    assertEquals(Math.PI * 0.5 - 0.01, bounds.getMinLatitude(), 0.01);
-
-    circle = new GeoStandardCircle(scaledModel, Math.PI * 0.25, 0.0, 0.01);
-    assertTrue(circle.isWithin(point1));
-    assertFalse(circle.isWithin(northPole));
-    assertFalse(circle.isWithin(southPole));
-    bounds = new LatLonBounds();
-    circle.getBounds(bounds);
-    assertFalse(bounds.checkNoTopLatitudeBound());
-    assertFalse(bounds.checkNoLongitudeBound());
-    assertFalse(bounds.checkNoBottomLatitudeBound());
-    assertEquals(Math.PI * 0.25 + 0.01, bounds.getMaxLatitude(), 0.00001);
-    assertEquals(Math.PI * 0.25 - 0.01, bounds.getMinLatitude(), 0.00001);
-    assertEquals(-0.0125, bounds.getLeftLongitude(), 0.0001);
-    assertEquals(0.0125, bounds.getRightLongitude(), 0.0001);
-
-    circle = new GeoStandardCircle(scaledModel, Math.PI * 0.125, 0.0, 0.01);
-    assertTrue(circle.isWithin(point2));
-    assertFalse(circle.isWithin(northPole));
-    assertFalse(circle.isWithin(southPole));
-    bounds = new LatLonBounds();
-    circle.getBounds(bounds);
-    assertFalse(bounds.checkNoLongitudeBound());
-    assertFalse(bounds.checkNoTopLatitudeBound());
-    assertFalse(bounds.checkNoBottomLatitudeBound());
-    // Symmetric, as expected
-    assertEquals(Math.PI * 0.125 - 0.01, bounds.getMinLatitude(), 0.00001);
-    assertEquals(Math.PI * 0.125 + 0.01, bounds.getMaxLatitude(), 0.00001);
-    assertEquals(-0.0089, bounds.getLeftLongitude(), 0.0001);
-    assertEquals(0.0089, bounds.getRightLongitude(), 0.0001);
-
-  }
-
-  @Test
-  public void testBasicRectangle() {
-    final GeoBBox bbox = GeoBBoxFactory.makeGeoBBox(scaledModel, 1.0, 0.0, 0.0, 1.0);
-    final GeoPoint insidePoint = new GeoPoint(scaledModel, 0.5, 0.5);
-    assertTrue(bbox.isWithin(insidePoint));
-    final GeoPoint topOutsidePoint = new GeoPoint(scaledModel, 1.01, 0.5);
-    assertFalse(bbox.isWithin(topOutsidePoint));
-    final GeoPoint bottomOutsidePoint = new GeoPoint(scaledModel, -0.01, 0.5);
-    assertFalse(bbox.isWithin(bottomOutsidePoint));
-    final GeoPoint leftOutsidePoint = new GeoPoint(scaledModel, 0.5, -0.01);
-    assertFalse(bbox.isWithin(leftOutsidePoint));
-    final GeoPoint rightOutsidePoint = new GeoPoint(scaledModel, 0.5, 1.01);
-    assertFalse(bbox.isWithin(rightOutsidePoint));
-    final LatLonBounds bounds = new LatLonBounds();
-    bbox.getBounds(bounds);
-    assertFalse(bounds.checkNoLongitudeBound());
-    assertFalse(bounds.checkNoTopLatitudeBound());
-    assertFalse(bounds.checkNoBottomLatitudeBound());
-    assertEquals(1.0, bounds.getMaxLatitude(), 0.00001);
-    assertEquals(0.0, bounds.getMinLatitude(), 0.00001);
-    assertEquals(1.0, bounds.getRightLongitude(), 0.00001);
-    assertEquals(0.0, bounds.getLeftLongitude(), 0.00001);
-  }
-  
-}
-
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoPathTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoPathTest.java b/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoPathTest.java
deleted file mode 100755
index fea7ed4..0000000
--- a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoPathTest.java
+++ /dev/null
@@ -1,270 +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.geo3d;
-
-import org.junit.Test;
-
-import static java.lang.Math.toRadians;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-public class GeoPathTest {
-
-  @Test
-  public void testPathDistance() {
-    // Start with a really simple case
-    GeoPath p;
-    GeoPoint gp;
-    p = new GeoPath(PlanetModel.SPHERE, 0.1);
-    p.addPoint(0.0, 0.0);
-    p.addPoint(0.0, 0.1);
-    p.addPoint(0.0, 0.2);
-    p.done();
-    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.5, 0.15);
-    assertEquals(Double.MAX_VALUE, p.computeDistance(DistanceStyle.ARC,gp), 0.0);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, 0.15);
-    assertEquals(0.15 + 0.05, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.12);
-    assertEquals(0.12 + 0.0, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.15, 0.05);
-    assertEquals(Double.MAX_VALUE, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.25);
-    assertEquals(0.20 + 0.05, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.05);
-    assertEquals(0.0 + 0.05, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
-
-    // Compute path distances now
-    p = new GeoPath(PlanetModel.SPHERE, 0.1);
-    p.addPoint(0.0, 0.0);
-    p.addPoint(0.0, 0.1);
-    p.addPoint(0.0, 0.2);
-    p.done();
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, 0.15);
-    assertEquals(0.15 + 0.05, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.12);
-    assertEquals(0.12, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
-
-    // Now try a vertical path, and make sure distances are as expected
-    p = new GeoPath(PlanetModel.SPHERE, 0.1);
-    p.addPoint(-Math.PI * 0.25, -0.5);
-    p.addPoint(Math.PI * 0.25, -0.5);
-    p.done();
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
-    assertEquals(Double.MAX_VALUE, p.computeDistance(DistanceStyle.ARC,gp), 0.0);
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -1.0);
-    assertEquals(Double.MAX_VALUE, p.computeDistance(DistanceStyle.ARC,gp), 0.0);
-    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.25 + 0.05, -0.5);
-    assertEquals(Math.PI * 0.5 + 0.05, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
-    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.25 - 0.05, -0.5);
-    assertEquals(0.0 + 0.05, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
-  }
-
-  @Test
-  public void testPathPointWithin() {
-    // Tests whether we can properly detect whether a point is within a path or not
-    GeoPath p;
-    GeoPoint gp;
-    p = new GeoPath(PlanetModel.SPHERE, 0.1);
-    // Build a diagonal path crossing the equator
-    p.addPoint(-0.2, -0.2);
-    p.addPoint(0.2, 0.2);
-    p.done();
-    // Test points on the path
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.2, -0.2);
-    assertTrue(p.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
-    assertTrue(p.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.1, 0.1);
-    assertTrue(p.isWithin(gp));
-    // Test points off the path
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.2, 0.2);
-    assertFalse(p.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0);
-    assertFalse(p.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.2, -0.2);
-    assertFalse(p.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
-    assertFalse(p.isWithin(gp));
-    // Repeat the test, but across the terminator
-    p = new GeoPath(PlanetModel.SPHERE, 0.1);
-    // Build a diagonal path crossing the equator
-    p.addPoint(-0.2, Math.PI - 0.2);
-    p.addPoint(0.2, -Math.PI + 0.2);
-    p.done();
-    // Test points on the path
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.2, Math.PI - 0.2);
-    assertTrue(p.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
-    assertTrue(p.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.1, -Math.PI + 0.1);
-    assertTrue(p.isWithin(gp));
-    // Test points off the path
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.2, -Math.PI + 0.2);
-    assertFalse(p.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0);
-    assertFalse(p.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.2, Math.PI - 0.2);
-    assertFalse(p.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
-    assertFalse(p.isWithin(gp));
-
-  }
-
-  @Test
-  public void testGetRelationship() {
-    GeoArea rect;
-    GeoPath p;
-    GeoPath c;
-    GeoPoint point;
-    GeoPoint pointApprox;
-    int relationship;
-    GeoArea area;
-    PlanetModel planetModel;
-    
-    planetModel = new PlanetModel(1.151145876105594, 0.8488541238944061);
-    c = new GeoPath(planetModel, 0.008726646259971648);
-    c.addPoint(-0.6925658899376476, 0.6316613927914589);
-    c.addPoint(0.27828548161836364, 0.6785795524104564);
-    c.done();
-    point = new GeoPoint(planetModel,-0.49298555067758226, 0.9892440995026406);
-    pointApprox = new GeoPoint(0.5110940362119821, 0.7774603209946239, -0.49984312299556544);
-    area = GeoAreaFactory.makeGeoArea(planetModel, 0.49937141144985997, 0.5161765426256085, 0.3337218719537796,0.8544419570901649, -0.6347692823688085, 0.3069696588119369);
-    assertTrue(!c.isWithin(point));
-    
-    // Start by testing the basic kinds of relationship, increasing in order of difficulty.
-
-    p = new GeoPath(PlanetModel.SPHERE, 0.1);
-    p.addPoint(-0.3, -0.3);
-    p.addPoint(0.3, 0.3);
-    p.done();
-    // Easiest: The path is wholly contains the georect
-    rect = new GeoRectangle(PlanetModel.SPHERE, 0.05, -0.05, -0.05, 0.05);
-    assertEquals(GeoArea.CONTAINS, rect.getRelationship(p));
-    // Next easiest: Some endpoints of the rectangle are inside, and some are outside.
-    rect = new GeoRectangle(PlanetModel.SPHERE, 0.05, -0.05, -0.05, 0.5);
-    assertEquals(GeoArea.OVERLAPS, rect.getRelationship(p));
-    // Now, all points are outside, but the figures intersect
-    rect = new GeoRectangle(PlanetModel.SPHERE, 0.05, -0.05, -0.5, 0.5);
-    assertEquals(GeoArea.OVERLAPS, rect.getRelationship(p));
-    // Finally, all points are outside, and the figures *do not* intersect
-    rect = new GeoRectangle(PlanetModel.SPHERE, 0.5, -0.5, -0.5, 0.5);
-    assertEquals(GeoArea.WITHIN, rect.getRelationship(p));
-    // Check that segment edge overlap detection works
-    rect = new GeoRectangle(PlanetModel.SPHERE, 0.1, 0.0, -0.1, 0.0);
-    assertEquals(GeoArea.OVERLAPS, rect.getRelationship(p));
-    rect = new GeoRectangle(PlanetModel.SPHERE, 0.2, 0.1, -0.2, -0.1);
-    assertEquals(GeoArea.DISJOINT, rect.getRelationship(p));
-    // Check if overlap at endpoints behaves as expected next
-    rect = new GeoRectangle(PlanetModel.SPHERE, 0.5, -0.5, -0.5, -0.35);
-    assertEquals(GeoArea.OVERLAPS, rect.getRelationship(p));
-    rect = new GeoRectangle(PlanetModel.SPHERE, 0.5, -0.5, -0.5, -0.45);
-    assertEquals(GeoArea.DISJOINT, rect.getRelationship(p));
-
-  }
-
-  @Test
-  public void testPathBounds() {
-    GeoPath c;
-    LatLonBounds b;
-    XYZBounds xyzb;
-    GeoPoint point;
-    int relationship;
-    GeoArea area;
-    PlanetModel planetModel;
-    
-    planetModel = new PlanetModel(0.751521665790406,1.248478334209594);
-    c = new GeoPath(planetModel, 0.7504915783575618);
-    c.addPoint(0.10869761172400265, 0.08895880215465272);
-    c.addPoint(0.22467878641991612, 0.10972973084229565);
-    c.addPoint(-0.7398772468744732, -0.4465812941383364);
-    c.addPoint(-0.18462055300079366, -0.6713857796763727);
-    c.done();
-    point = new GeoPoint(planetModel,-0.626645355125733,-1.409304625439381);
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(planetModel,
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    relationship = area.getRelationship(c);
-    assertTrue(relationship == GeoArea.WITHIN || relationship == GeoArea.OVERLAPS);
-    assertTrue(area.isWithin(point));
-    // No longer true due to fixed GeoPath waypoints.
-    //assertTrue(c.isWithin(point));
-    
-    c = new GeoPath(PlanetModel.WGS84, 0.6894050545377601);
-    c.addPoint(-0.0788176065762948, 0.9431251741731624);
-    c.addPoint(0.510387871458147, 0.5327078872484678);
-    c.addPoint(-0.5624521609859962, 1.5398841746888388);
-    c.addPoint(-0.5025171434638661, -0.5895998642788894);
-    c.done();
-    point = new GeoPoint(PlanetModel.WGS84, 0.023652082107211682, 0.023131910152748437);
-    //System.err.println("Point.x = "+point.x+"; point.y="+point.y+"; point.z="+point.z);
-    assertTrue(c.isWithin(point));
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84,
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    //System.err.println("minx="+xyzb.getMinimumX()+" maxx="+xyzb.getMaximumX()+" miny="+xyzb.getMinimumY()+" maxy="+xyzb.getMaximumY()+" minz="+xyzb.getMinimumZ()+" maxz="+xyzb.getMaximumZ());
-    //System.err.println("point.x="+point.x+" point.y="+point.y+" point.z="+point.z);
-    relationship = area.getRelationship(c);
-    assertTrue(relationship == GeoArea.WITHIN || relationship == GeoArea.OVERLAPS);
-    assertTrue(area.isWithin(point));
-    
-    c = new GeoPath(PlanetModel.WGS84, 0.7766715171374766);
-    c.addPoint(-0.2751718361148076, -0.7786721269011477);
-    c.addPoint(0.5728375851539309, -1.2700115736820465);
-    c.done();
-    point = new GeoPoint(PlanetModel.WGS84, -0.01580760332365284, -0.03956004622490505);
-    assertTrue(c.isWithin(point));
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84,
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    //System.err.println("minx="+xyzb.getMinimumX()+" maxx="+xyzb.getMaximumX()+" miny="+xyzb.getMinimumY()+" maxy="+xyzb.getMaximumY()+" minz="+xyzb.getMinimumZ()+" maxz="+xyzb.getMaximumZ());
-    //System.err.println("point.x="+point.x+" point.y="+point.y+" point.z="+point.z);
-    relationship = area.getRelationship(c);
-    assertTrue(relationship == GeoArea.WITHIN || relationship == GeoArea.OVERLAPS);
-    assertTrue(area.isWithin(point));
-
-    c = new GeoPath(PlanetModel.SPHERE, 0.1);
-    c.addPoint(-0.3, -0.3);
-    c.addPoint(0.3, 0.3);
-    c.done();
-
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(-0.4046919, b.getLeftLongitude(), 0.000001);
-    assertEquals(0.4046919, b.getRightLongitude(), 0.000001);
-    assertEquals(-0.3999999, b.getMinLatitude(), 0.000001);
-    assertEquals(0.3999999, b.getMaxLatitude(), 0.000001);
-
-  }
-
-  @Test
-  public void testCoLinear() {
-    // p1: (12,-90), p2: (11, -55), (129, -90)
-    GeoPath p = new GeoPath(PlanetModel.SPHERE, 0.1);
-    p.addPoint(toRadians(-90), toRadians(12));//south pole
-    p.addPoint(toRadians(-55), toRadians(11));
-    p.addPoint(toRadians(-90), toRadians(129));//south pole again
-    p.done();//at least test this doesn't bomb like it used too -- LUCENE-6520
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoPolygonTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoPolygonTest.java b/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoPolygonTest.java
deleted file mode 100755
index f1511b9..0000000
--- a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/GeoPolygonTest.java
+++ /dev/null
@@ -1,165 +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.geo3d;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-public class GeoPolygonTest {
-
-
-  @Test
-  public void testPolygonPointWithin() {
-    GeoMembershipShape c;
-    GeoPoint gp;
-    List<GeoPoint> points;
-
-    points = new ArrayList<GeoPoint>();
-    points.add(new GeoPoint(PlanetModel.SPHERE, -0.1, -0.5));
-    points.add(new GeoPoint(PlanetModel.SPHERE, 0.0, -0.6));
-    points.add(new GeoPoint(PlanetModel.SPHERE, 0.1, -0.5));
-    points.add(new GeoPoint(PlanetModel.SPHERE, 0.0, -0.4));
-
-    c = GeoPolygonFactory.makeGeoPolygon(PlanetModel.SPHERE, points, 0);
-    // Sample some points within
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.55);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.45);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.05, -0.5);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, -0.5);
-    assertTrue(c.isWithin(gp));
-    // Sample some nearby points outside
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.65);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.35);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.15, -0.5);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.15, -0.5);
-    assertFalse(c.isWithin(gp));
-    // Random points outside
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.5, 0.0);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
-    assertFalse(c.isWithin(gp));
-
-    points = new ArrayList<GeoPoint>();
-    points.add(new GeoPoint(PlanetModel.SPHERE, -0.1, -0.5));
-    points.add(new GeoPoint(PlanetModel.SPHERE, -0.01, -0.6));
-    points.add(new GeoPoint(PlanetModel.SPHERE, -0.1, -0.7));
-    points.add(new GeoPoint(PlanetModel.SPHERE, 0.0, -0.8));
-    points.add(new GeoPoint(PlanetModel.SPHERE, 0.1, -0.7));
-    points.add(new GeoPoint(PlanetModel.SPHERE, 0.01, -0.6));
-    points.add(new GeoPoint(PlanetModel.SPHERE, 0.1, -0.5));
-    points.add(new GeoPoint(PlanetModel.SPHERE, 0.0, -0.4));
-        
-        /*
-        System.out.println("Points: ");
-        for (GeoPoint p : points) {
-            System.out.println(" "+p);
-        }
-        */
-
-    c = GeoPolygonFactory.makeGeoPolygon(PlanetModel.SPHERE, points, 0);
-    // Sample some points within
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.55);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.45);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.05, -0.5);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, -0.5);
-    assertTrue(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.7);
-    assertTrue(c.isWithin(gp));
-    // Sample some nearby points outside
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.35);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, -0.15, -0.5);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.15, -0.5);
-    assertFalse(c.isWithin(gp));
-    // Random points outside
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.5, 0.0);
-    assertFalse(c.isWithin(gp));
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
-    assertFalse(c.isWithin(gp));
-
-  }
-
-  @Test
-  public void testPolygonBounds() {
-    GeoMembershipShape c;
-    LatLonBounds b;
-    List<GeoPoint> points;
-    XYZBounds xyzb;
-    GeoPoint point;
-    GeoArea area;
-    
-    // BKD failure
-    points = new ArrayList<GeoPoint>();
-    points.add(new GeoPoint(PlanetModel.WGS84, -0.36716183577912814, 1.4836349969188696));
-    points.add(new GeoPoint(PlanetModel.WGS84, 0.7846038240742979, -0.02743348424931823));
-    points.add(new GeoPoint(PlanetModel.WGS84, -0.7376479402362607, -0.5072961758807019));
-    points.add(new GeoPoint(PlanetModel.WGS84, -0.3760415907667887, 1.4970455334565513));
-    
-    c = GeoPolygonFactory.makeGeoPolygon(PlanetModel.WGS84, points, 1);
-    
-    point = new GeoPoint(PlanetModel.WGS84, -0.01580760332365284, -0.03956004622490505);
-    assertTrue(c.isWithin(point));
-    xyzb = new XYZBounds();
-    c.getBounds(xyzb);
-    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84,
-      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
-    assertTrue(area.isWithin(point));
-    
-    points = new ArrayList<GeoPoint>();
-    points.add(new GeoPoint(PlanetModel.SPHERE, -0.1, -0.5));
-    points.add(new GeoPoint(PlanetModel.SPHERE, 0.0, -0.6));
-    points.add(new GeoPoint(PlanetModel.SPHERE, 0.1, -0.5));
-    points.add(new GeoPoint(PlanetModel.SPHERE, 0.0, -0.4));
-
-    c = GeoPolygonFactory.makeGeoPolygon(PlanetModel.SPHERE, points, 0);
-
-    b = new LatLonBounds();
-    c.getBounds(b);
-    assertFalse(b.checkNoLongitudeBound());
-    assertFalse(b.checkNoTopLatitudeBound());
-    assertFalse(b.checkNoBottomLatitudeBound());
-    assertEquals(-0.6, b.getLeftLongitude(), 0.000001);
-    assertEquals(-0.4, b.getRightLongitude(), 0.000001);
-    assertEquals(-0.1, b.getMinLatitude(), 0.000001);
-    assertEquals(0.1, b.getMaxLatitude(), 0.000001);
-  }
-
-}


[24/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 3a31a8c)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoLongitudeSlice.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoLongitudeSlice.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoLongitudeSlice.java
new file mode 100755
index 0000000..458cf8b
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoLongitudeSlice.java
@@ -0,0 +1,204 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Bounding box limited on left and right.
+ * The left-right maximum extent for this shape is PI; for anything larger, use
+ * {@link GeoWideLongitudeSlice}.
+ *
+ * @lucene.internal
+ */
+public class GeoLongitudeSlice extends GeoBaseBBox {
+  /** The left longitude of the slice */
+  protected final double leftLon;
+  /** The right longitude of the slice */
+  protected final double rightLon;
+  /** The left plane of the slice */
+  protected final SidedPlane leftPlane;
+  /** The right plane of the slice */
+  protected final SidedPlane rightPlane;
+  /** The notable points for the slice (north and south poles) */
+  protected final GeoPoint[] planePoints;
+  /** The center point of the slice */
+  protected final GeoPoint centerPoint;
+  /** A point on the edge of the slice */
+  protected final GeoPoint[] edgePoints;
+
+  /**
+   * Accepts only values in the following ranges: lon: {@code -PI -> PI}
+   *@param planetModel is the planet model.
+   *@param leftLon is the left longitude of the slice.
+   *@param rightLon is the right longitude of the slice.
+   */
+  public GeoLongitudeSlice(final PlanetModel planetModel, final double leftLon, double rightLon) {
+    super(planetModel);
+    // Argument checking
+    if (leftLon < -Math.PI || leftLon > Math.PI)
+      throw new IllegalArgumentException("Left longitude out of range");
+    if (rightLon < -Math.PI || rightLon > Math.PI)
+      throw new IllegalArgumentException("Right longitude out of range");
+    double extent = rightLon - leftLon;
+    if (extent < 0.0) {
+      extent += 2.0 * Math.PI;
+    }
+    if (extent > Math.PI)
+      throw new IllegalArgumentException("Width of rectangle too great");
+
+    this.leftLon = leftLon;
+    this.rightLon = rightLon;
+
+    final double sinLeftLon = Math.sin(leftLon);
+    final double cosLeftLon = Math.cos(leftLon);
+    final double sinRightLon = Math.sin(rightLon);
+    final double cosRightLon = Math.cos(rightLon);
+
+    // Normalize
+    while (leftLon > rightLon) {
+      rightLon += Math.PI * 2.0;
+    }
+    final double middleLon = (leftLon + rightLon) * 0.5;
+    this.centerPoint = new GeoPoint(planetModel, 0.0, middleLon);
+
+    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
+    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
+
+    this.planePoints = new GeoPoint[]{planetModel.NORTH_POLE, planetModel.SOUTH_POLE};
+    this.edgePoints = new GeoPoint[]{planetModel.NORTH_POLE};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    // Figuring out when we escalate to a special case requires some prefiguring
+    double currentLonSpan = rightLon - leftLon;
+    if (currentLonSpan < 0.0)
+      currentLonSpan += Math.PI * 2.0;
+    double newLeftLon = leftLon - angle;
+    double newRightLon = rightLon + angle;
+    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
+      newLeftLon = -Math.PI;
+      newRightLon = Math.PI;
+    }
+    return GeoBBoxFactory.makeGeoBBox(planetModel, Math.PI * 0.5, -Math.PI * 0.5, newLeftLon, newRightLon);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return leftPlane.isWithin(x, y, z) &&
+        rightPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public double getRadius() {
+    // Compute the extent and divide by two
+    double extent = rightLon - leftLon;
+    if (extent < 0.0)
+      extent += Math.PI * 2.0;
+    return Math.max(Math.PI * 0.5, extent * 0.5);
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    return centerPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return p.intersects(planetModel, leftPlane, notablePoints, planePoints, bounds, rightPlane) ||
+        p.intersects(planetModel, rightPlane, notablePoints, planePoints, bounds, leftPlane);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds
+      .addVerticalPlane(planetModel, leftLon, leftPlane, rightPlane)
+      .addVerticalPlane(planetModel, rightLon, rightPlane, leftPlane)
+      .addPoint(planetModel.NORTH_POLE)
+      .addPoint(planetModel.SOUTH_POLE);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    final int insideRectangle = isShapeInsideBBox(path);
+    if (insideRectangle == SOME_INSIDE)
+      return OVERLAPS;
+
+    final boolean insideShape = path.isWithin(planetModel.NORTH_POLE);
+
+    if (insideRectangle == ALL_INSIDE && insideShape)
+      return OVERLAPS;
+
+    if (path.intersects(leftPlane, planePoints, rightPlane) ||
+        path.intersects(rightPlane, planePoints, leftPlane)) {
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      return WITHIN;
+    }
+
+    if (insideShape) {
+      return CONTAINS;
+    }
+
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, rightPlane);
+    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, leftPlane);
+    
+    final double northDistance = distanceStyle.computeDistance(planetModel.NORTH_POLE, x,y,z);
+    final double southDistance = distanceStyle.computeDistance(planetModel.SOUTH_POLE, x,y,z);
+    
+    return
+      Math.min(
+        Math.min(northDistance, southDistance),
+        Math.min(leftDistance, rightDistance));
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoLongitudeSlice))
+      return false;
+    GeoLongitudeSlice other = (GeoLongitudeSlice) o;
+    return super.equals(other) && other.leftLon == leftLon && other.rightLon == rightLon;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    long temp = Double.doubleToLongBits(leftLon);
+    result = 31 * result + (int) (temp ^ (temp >>> 32));
+    temp = Double.doubleToLongBits(rightLon);
+    result = 31 * result + (int) (temp ^ (temp >>> 32));
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoLongitudeSlice: {planetmodel="+planetModel+", leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
+  }
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoMembershipShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoMembershipShape.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoMembershipShape.java
new file mode 100755
index 0000000..2c47971
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoMembershipShape.java
@@ -0,0 +1,27 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Membership shapes have capabilities of both geohashing and membership
+ * determination.
+ *
+ * @lucene.experimental
+ */
+public interface GeoMembershipShape extends GeoShape, GeoOutsideDistance, Membership {
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoNorthLatitudeZone.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoNorthLatitudeZone.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoNorthLatitudeZone.java
new file mode 100644
index 0000000..2c94061
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoNorthLatitudeZone.java
@@ -0,0 +1,165 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * This GeoBBox represents an area rectangle limited only in south latitude.
+ *
+ * @lucene.internal
+ */
+public class GeoNorthLatitudeZone extends GeoBaseBBox {
+  /** The bottom latitude of the zone */
+  protected final double bottomLat;
+  /** Cosine of the bottom latitude of the zone */
+  protected final double cosBottomLat;
+  /** The bottom plane of the zone */
+  protected final SidedPlane bottomPlane;
+  /** An interior point of the zone */
+  protected final GeoPoint interiorPoint;
+  /** Notable points: none */
+  protected final static GeoPoint[] planePoints = new GeoPoint[0];
+  /** A point on the bottom boundary */
+  protected final GeoPoint bottomBoundaryPoint;
+  /** A reference to the point on the boundary */
+  protected final GeoPoint[] edgePoints;
+
+  /** Constructor.
+   *@param planetModel is the planet model.
+   *@param bottomLat is the bottom latitude.
+   */
+  public GeoNorthLatitudeZone(final PlanetModel planetModel, final double bottomLat) {
+    super(planetModel);
+    this.bottomLat = bottomLat;
+
+    final double sinBottomLat = Math.sin(bottomLat);
+    this.cosBottomLat = Math.cos(bottomLat);
+
+    // Compute an interior point.  Pick one whose lat is between top and bottom.
+    final double middleLat = (Math.PI * 0.5 + bottomLat) * 0.5;
+    final double sinMiddleLat = Math.sin(middleLat);
+    this.interiorPoint = new GeoPoint(planetModel, sinMiddleLat, 0.0, Math.sqrt(1.0 - sinMiddleLat * sinMiddleLat), 1.0);
+    this.bottomBoundaryPoint = new GeoPoint(planetModel, sinBottomLat, 0.0, Math.sqrt(1.0 - sinBottomLat * sinBottomLat), 1.0);
+
+    this.bottomPlane = new SidedPlane(interiorPoint, planetModel, sinBottomLat);
+
+    this.edgePoints = new GeoPoint[]{bottomBoundaryPoint};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    final double newTopLat = Math.PI * 0.5;
+    final double newBottomLat = bottomLat - angle;
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, -Math.PI, Math.PI);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return
+        bottomPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public double getRadius() {
+    // This is a bit tricky.  I guess we should interpret this as meaning the angle of a circle that
+    // would contain all the bounding box points, when starting in the "center".
+    if (bottomLat < 0.0)
+      return Math.PI;
+    double maxCosLat = cosBottomLat;
+    return maxCosLat * Math.PI;
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    return interiorPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return
+        p.intersects(planetModel, bottomPlane, notablePoints, planePoints, bounds);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds
+      .addHorizontalPlane(planetModel, bottomLat, bottomPlane);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    final int insideRectangle = isShapeInsideBBox(path);
+    if (insideRectangle == SOME_INSIDE)
+      return OVERLAPS;
+
+    final boolean insideShape = path.isWithin(bottomBoundaryPoint);
+
+    if (insideRectangle == ALL_INSIDE && insideShape)
+      return OVERLAPS;
+
+    // Second, the shortcut of seeing whether endpoints are in/out is not going to
+    // work with no area endpoints.  So we rely entirely on intersections.
+
+    if (path.intersects(bottomPlane, planePoints))
+      return OVERLAPS;
+
+    // There is another case for latitude zones only.  This is when the boundaries of the shape all fit
+    // within the zone, but the shape includes areas outside the zone crossing a pole.
+    // In this case, the above "overlaps" check is insufficient.  We also need to check a point on either boundary
+    // whether it is within the shape.  If both such points are within, then CONTAINS is the right answer.  If
+    // one such point is within, then OVERLAPS is the right answer.
+
+    if (insideShape)
+      return CONTAINS;
+
+    if (insideRectangle == ALL_INSIDE)
+      return WITHIN;
+
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    return distanceStyle.computeDistance(planetModel, bottomPlane, x,y,z);
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoNorthLatitudeZone))
+      return false;
+    GeoNorthLatitudeZone other = (GeoNorthLatitudeZone) o;
+    return super.equals(other) && other.bottomBoundaryPoint.equals(bottomBoundaryPoint);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + bottomBoundaryPoint.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoNorthLatitudeZone: {planetmodel="+planetModel+", bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + ")}";
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoNorthRectangle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoNorthRectangle.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoNorthRectangle.java
new file mode 100644
index 0000000..a2b6f1b
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoNorthRectangle.java
@@ -0,0 +1,263 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Bounding box limited on three sides (bottom lat, left lon, right lon), including
+ * the north pole.
+ * The left-right maximum extent for this shape is PI; for anything larger, use
+ * {@link GeoWideNorthRectangle}.
+ *
+ * @lucene.internal
+ */
+public class GeoNorthRectangle extends GeoBaseBBox {
+  /** The bottom latitude of the rectangle */
+  protected final double bottomLat;
+  /** The left longitude */
+  protected final double leftLon;
+  /** The right longitude */
+  protected final double rightLon;
+  /** Cosine of the middle latitude */
+  protected final double cosMiddleLat;
+  /** Lower right hand corner point */
+  protected final GeoPoint LRHC;
+  /** Lower left hand corner point */
+  protected final GeoPoint LLHC;
+  /** Bottom edge plane */
+  protected final SidedPlane bottomPlane;
+  /** Left-side plane */
+  protected final SidedPlane leftPlane;
+  /** Right-side plane */
+  protected final SidedPlane rightPlane;
+  /** Bottom plane notable points */
+  protected final GeoPoint[] bottomPlanePoints;
+  /** Left plane notable points */
+  protected final GeoPoint[] leftPlanePoints;
+  /** Right plane notable points */
+  protected final GeoPoint[] rightPlanePoints;
+  /** Center point */
+  protected final GeoPoint centerPoint;
+  /** A point on the edge */
+  protected final GeoPoint[] edgePoints;
+
+  /**
+   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
+   *@param planetModel is the planet model.
+   *@param bottomLat is the bottom latitude.
+   *@param leftLon is the left longitude.
+   *@param rightLon is the right longitude.
+   */
+  public GeoNorthRectangle(final PlanetModel planetModel, final double bottomLat, final double leftLon, double rightLon) {
+    super(planetModel);
+    // Argument checking
+    if (bottomLat > Math.PI * 0.5 || bottomLat < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Bottom latitude out of range");
+    if (leftLon < -Math.PI || leftLon > Math.PI)
+      throw new IllegalArgumentException("Left longitude out of range");
+    if (rightLon < -Math.PI || rightLon > Math.PI)
+      throw new IllegalArgumentException("Right longitude out of range");
+    double extent = rightLon - leftLon;
+    if (extent < 0.0) {
+      extent += 2.0 * Math.PI;
+    }
+    if (extent > Math.PI)
+      throw new IllegalArgumentException("Width of rectangle too great");
+
+    this.bottomLat = bottomLat;
+    this.leftLon = leftLon;
+    this.rightLon = rightLon;
+
+    final double sinBottomLat = Math.sin(bottomLat);
+    final double cosBottomLat = Math.cos(bottomLat);
+    final double sinLeftLon = Math.sin(leftLon);
+    final double cosLeftLon = Math.cos(leftLon);
+    final double sinRightLon = Math.sin(rightLon);
+    final double cosRightLon = Math.cos(rightLon);
+
+    // Now build the points
+    this.LRHC = new GeoPoint(planetModel, sinBottomLat, sinRightLon, cosBottomLat, cosRightLon, bottomLat, rightLon);
+    this.LLHC = new GeoPoint(planetModel, sinBottomLat, sinLeftLon, cosBottomLat, cosLeftLon, bottomLat, leftLon);
+
+    final double middleLat = (Math.PI * 0.5 + bottomLat) * 0.5;
+    final double sinMiddleLat = Math.sin(middleLat);
+    this.cosMiddleLat = Math.cos(middleLat);
+    // Normalize
+    while (leftLon > rightLon) {
+      rightLon += Math.PI * 2.0;
+    }
+    final double middleLon = (leftLon + rightLon) * 0.5;
+    final double sinMiddleLon = Math.sin(middleLon);
+    final double cosMiddleLon = Math.cos(middleLon);
+
+    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinMiddleLon, cosMiddleLat, cosMiddleLon);
+
+    this.bottomPlane = new SidedPlane(centerPoint, planetModel, sinBottomLat);
+    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
+    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
+
+    this.bottomPlanePoints = new GeoPoint[]{LLHC, LRHC};
+    this.leftPlanePoints = new GeoPoint[]{planetModel.NORTH_POLE, LLHC};
+    this.rightPlanePoints = new GeoPoint[]{planetModel.NORTH_POLE, LRHC};
+
+    this.edgePoints = new GeoPoint[]{planetModel.NORTH_POLE};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    final double newTopLat = Math.PI * 0.5;
+    final double newBottomLat = bottomLat - angle;
+    // Figuring out when we escalate to a special case requires some prefiguring
+    double currentLonSpan = rightLon - leftLon;
+    if (currentLonSpan < 0.0)
+      currentLonSpan += Math.PI * 2.0;
+    double newLeftLon = leftLon - angle;
+    double newRightLon = rightLon + angle;
+    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
+      newLeftLon = -Math.PI;
+      newRightLon = Math.PI;
+    }
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return
+        bottomPlane.isWithin(x, y, z) &&
+            leftPlane.isWithin(x, y, z) &&
+            rightPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public double getRadius() {
+    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
+    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
+    // the distance to the right or left edge from the center.
+    final double centerAngle = (rightLon - (rightLon + leftLon) * 0.5) * cosMiddleLat;
+    final double bottomAngle = centerPoint.arcDistance(LLHC);
+    return Math.max(centerAngle, bottomAngle);
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  /**
+   * Returns the center of a circle into which the area will be inscribed.
+   *
+   * @return the center.
+   */
+  @Override
+  public GeoPoint getCenter() {
+    return centerPoint;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return
+        p.intersects(planetModel, bottomPlane, notablePoints, bottomPlanePoints, bounds, leftPlane, rightPlane) ||
+            p.intersects(planetModel, leftPlane, notablePoints, leftPlanePoints, bounds, rightPlane, bottomPlane) ||
+            p.intersects(planetModel, rightPlane, notablePoints, rightPlanePoints, bounds, leftPlane, bottomPlane);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds
+      .addHorizontalPlane(planetModel, bottomLat, bottomPlane, leftPlane, rightPlane)
+      .addVerticalPlane(planetModel, leftLon, leftPlane, bottomPlane, rightPlane)
+      .addVerticalPlane(planetModel, rightLon, rightPlane, bottomPlane, leftPlane)
+      .addPoint(LLHC).addPoint(LRHC).addPoint(planetModel.NORTH_POLE);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    //System.err.println(this+" getrelationship with "+path);
+    final int insideRectangle = isShapeInsideBBox(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some inside");
+      return OVERLAPS;
+    }
+
+    final boolean insideShape = path.isWithin(planetModel.NORTH_POLE);
+
+    if (insideRectangle == ALL_INSIDE && insideShape) {
+      //System.err.println(" inside of each other");
+      return OVERLAPS;
+    }
+
+    if (
+        path.intersects(bottomPlane, bottomPlanePoints, leftPlane, rightPlane) ||
+            path.intersects(leftPlane, leftPlanePoints, bottomPlane, rightPlane) ||
+            path.intersects(rightPlane, rightPlanePoints, leftPlane, bottomPlane)) {
+      //System.err.println(" edges intersect");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      //System.err.println(" shape inside rectangle");
+      return WITHIN;
+    }
+
+    if (insideShape) {
+      //System.err.println(" shape contains rectangle");
+      return CONTAINS;
+    }
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    final double bottomDistance = distanceStyle.computeDistance(planetModel, bottomPlane, x,y,z, leftPlane, rightPlane);
+    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, rightPlane, bottomPlane);
+    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, leftPlane, bottomPlane);
+    
+    final double LRHCDistance = distanceStyle.computeDistance(LRHC, x,y,z);
+    final double LLHCDistance = distanceStyle.computeDistance(LLHC, x,y,z);
+    
+    return
+      Math.min(
+        bottomDistance,
+        Math.min(
+          Math.min(leftDistance, rightDistance),
+          Math.min(LRHCDistance, LLHCDistance)));
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoNorthRectangle))
+      return false;
+    GeoNorthRectangle other = (GeoNorthRectangle) o;
+    return super.equals(other) && other.LLHC.equals(LLHC) && other.LRHC.equals(LRHC);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + LLHC.hashCode();
+    result = 31 * result + LRHC.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoNorthRectangle: {planetmodel="+planetModel+", bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
+  }
+}
+  
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoOutsideDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoOutsideDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoOutsideDistance.java
new file mode 100644
index 0000000..717854c
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoOutsideDistance.java
@@ -0,0 +1,55 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Implemented by Geo3D shapes that can compute the distance from a point to the closest outside edge.
+ *
+ * @lucene.experimental
+ */
+public interface GeoOutsideDistance extends Membership {
+  
+  // The following methods compute distances from the shape to a point
+  // expected to be OUTSIDE the shape.  Typically a value of 0.0
+  // is returned for points that happen to be within the shape.
+  
+  /**
+   * Compute this shape's distance to the GeoPoint.
+   * A return value of 0.0 should be returned for
+   * points inside of the shape.
+   * @param distanceStyle is the distance style.
+   * @param point is the point to compute the distance to.
+   * @return the distance.
+   */
+  public default double computeOutsideDistance(final DistanceStyle distanceStyle, final GeoPoint point) {
+    return computeOutsideDistance(distanceStyle, point.x, point.y, point.z);
+  }
+
+  /**
+   * Compute this shape's distance to the GeoPoint.
+   * A return value of 0.0 should be returned for
+   * points inside of the shape.
+   * @param distanceStyle is the distance style.
+   * @param x is the point's unit x coordinate (using U.S. convention).
+   * @param y is the point's unit y coordinate (using U.S. convention).
+   * @param z is the point's unit z coordinate (using U.S. convention).
+   * @return the distance.
+   */
+  public double computeOutsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z);
+
+}
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPath.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPath.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPath.java
new file mode 100755
index 0000000..a5b8b9b
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPath.java
@@ -0,0 +1,797 @@
+/*
+ * 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.spatial3d.geom;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * GeoShape representing a path across the surface of the globe,
+ * with a specified half-width.  Path is described by a series of points.
+ * Distances are measured from the starting point along the path, and then at right
+ * angles to the path.
+ *
+ * @lucene.experimental
+ */
+public class GeoPath extends GeoBaseDistanceShape {
+  /** The cutoff angle (width) */
+  protected final double cutoffAngle;
+
+  /** Sine of cutoff angle */
+  protected final double sinAngle;
+  /** Cosine of cutoff angle */
+  protected final double cosAngle;
+
+  /** The original list of path points */
+  protected final List<GeoPoint> points = new ArrayList<GeoPoint>();
+  
+  /** A list of SegmentEndpoints */
+  protected List<SegmentEndpoint> endPoints;
+  /** A list of PathSegments */
+  protected List<PathSegment> segments;
+
+  /** A point on the edge */
+  protected GeoPoint[] edgePoints;
+
+  /** Set to true if path has been completely constructed */
+  protected boolean isDone = false;
+  
+  /** Constructor.
+   *@param planetModel is the planet model.
+   *@param maxCutoffAngle is the width of the path, measured as an angle.
+   *@param pathPoints are the points in the path.
+   */
+  public GeoPath(final PlanetModel planetModel, final double maxCutoffAngle, final GeoPoint[] pathPoints) {
+    this(planetModel, maxCutoffAngle);
+    Collections.addAll(points, pathPoints);
+    done();
+  }
+  
+  /** Piece-wise constructor.  Use in conjunction with addPoint() and done().
+   *@param planetModel is the planet model.
+   *@param maxCutoffAngle is the width of the path, measured as an angle.
+   */
+  public GeoPath(final PlanetModel planetModel, final double maxCutoffAngle) {
+    super(planetModel);
+    if (maxCutoffAngle <= 0.0 || maxCutoffAngle > Math.PI * 0.5)
+      throw new IllegalArgumentException("Cutoff angle out of bounds");
+    this.cutoffAngle = maxCutoffAngle;
+    this.cosAngle = Math.cos(maxCutoffAngle);
+    this.sinAngle = Math.sin(maxCutoffAngle);
+  }
+
+  /** Add a point to the path.
+   *@param lat is the latitude of the point.
+   *@param lon is the longitude of the point.
+   */
+  public void addPoint(final double lat, final double lon) {
+    if (isDone)
+      throw new IllegalStateException("Can't call addPoint() if done() already called");
+    points.add(new GeoPoint(planetModel, lat, lon));
+  }
+  
+  /** Complete the path.
+   */
+  public void done() {
+    if (isDone)
+      throw new IllegalStateException("Can't call done() twice");
+    if (points.size() == 0)
+      throw new IllegalArgumentException("Path must have at least one point");
+    isDone = true;
+
+    endPoints = new ArrayList<>(points.size());
+    segments = new ArrayList<>(points.size());
+    // Compute an offset to use for all segments.  This will be based on the minimum magnitude of
+    // the entire ellipsoid.
+    final double cutoffOffset = this.sinAngle * planetModel.getMinimumMagnitude();
+    
+    // First, build all segments.  We'll then go back and build corresponding segment endpoints.
+    GeoPoint lastPoint = null;
+    for (final GeoPoint end : points) {
+      if (lastPoint != null) {
+        final Plane normalizedConnectingPlane = new Plane(lastPoint, end);
+        if (normalizedConnectingPlane == null) {
+          continue;
+        }
+        segments.add(new PathSegment(planetModel, lastPoint, end, normalizedConnectingPlane, cutoffOffset));
+      }
+      lastPoint = end;
+    }
+    
+    if (segments.size() == 0) {
+      // Simple circle
+      double lat = points.get(0).getLatitude();
+      double lon = points.get(0).getLongitude();
+      // Compute two points on the circle, with the right angle from the center.  We'll use these
+      // to obtain the perpendicular plane to the circle.
+      double upperLat = lat + cutoffAngle;
+      double upperLon = lon;
+      if (upperLat > Math.PI * 0.5) {
+        upperLon += Math.PI;
+        if (upperLon > Math.PI)
+          upperLon -= 2.0 * Math.PI;
+        upperLat = Math.PI - upperLat;
+      }
+      double lowerLat = lat - cutoffAngle;
+      double lowerLon = lon;
+      if (lowerLat < -Math.PI * 0.5) {
+        lowerLon += Math.PI;
+        if (lowerLon > Math.PI)
+          lowerLon -= 2.0 * Math.PI;
+        lowerLat = -Math.PI - lowerLat;
+      }
+      final GeoPoint upperPoint = new GeoPoint(planetModel, upperLat, upperLon);
+      final GeoPoint lowerPoint = new GeoPoint(planetModel, lowerLat, lowerLon);
+      final GeoPoint point = points.get(0);
+      
+      // Construct normal plane
+      final Plane normalPlane = Plane.constructNormalizedZPlane(upperPoint, lowerPoint, point);
+
+      final SegmentEndpoint onlyEndpoint = new SegmentEndpoint(point, normalPlane, upperPoint, lowerPoint);
+      endPoints.add(onlyEndpoint);
+      this.edgePoints = new GeoPoint[]{onlyEndpoint.circlePlane.getSampleIntersectionPoint(planetModel, normalPlane)};
+      return;
+    }
+    
+    // Create segment endpoints.  Use an appropriate constructor for the start and end of the path.
+    for (int i = 0; i < segments.size(); i++) {
+      final PathSegment currentSegment = segments.get(i);
+      
+      if (i == 0) {
+        // Starting endpoint
+        final SegmentEndpoint startEndpoint = new SegmentEndpoint(currentSegment.start, 
+          currentSegment.startCutoffPlane, currentSegment.ULHC, currentSegment.LLHC);
+        endPoints.add(startEndpoint);
+        this.edgePoints = new GeoPoint[]{currentSegment.ULHC};
+        continue;
+      }
+      
+      // General intersection case
+      final PathSegment prevSegment = segments.get(i-1);
+      // We construct four separate planes, and evaluate which one includes all interior points with least overlap
+      final SidedPlane candidate1 = SidedPlane.constructNormalizedThreePointSidedPlane(currentSegment.start, prevSegment.URHC, currentSegment.ULHC, currentSegment.LLHC);
+      final SidedPlane candidate2 = SidedPlane.constructNormalizedThreePointSidedPlane(currentSegment.start, currentSegment.ULHC, currentSegment.LLHC, prevSegment.LRHC);
+      final SidedPlane candidate3 = SidedPlane.constructNormalizedThreePointSidedPlane(currentSegment.start, currentSegment.LLHC, prevSegment.LRHC, prevSegment.URHC);
+      final SidedPlane candidate4 = SidedPlane.constructNormalizedThreePointSidedPlane(currentSegment.start, prevSegment.LRHC, prevSegment.URHC, currentSegment.ULHC);
+
+      if (candidate1 == null && candidate2 == null && candidate3 == null && candidate4 == null) {
+        // The planes are identical.  We wouldn't need a circle at all except for the possibility of
+        // backing up, which is hard to detect here.
+        final SegmentEndpoint midEndpoint = new SegmentEndpoint(currentSegment.start, 
+          prevSegment.endCutoffPlane, currentSegment.startCutoffPlane, currentSegment.ULHC, currentSegment.LLHC);
+        //don't need a circle at all.  Special constructor...
+        endPoints.add(midEndpoint);
+      } else {
+        endPoints.add(new SegmentEndpoint(currentSegment.start,
+          prevSegment.endCutoffPlane, currentSegment.startCutoffPlane,
+          prevSegment.URHC, prevSegment.LRHC,
+          currentSegment.ULHC, currentSegment.LLHC,
+          candidate1, candidate2, candidate3, candidate4));
+      }
+    }
+    // Do final endpoint
+    final PathSegment lastSegment = segments.get(segments.size()-1);
+    endPoints.add(new SegmentEndpoint(lastSegment.end,
+      lastSegment.endCutoffPlane, lastSegment.URHC, lastSegment.LRHC));
+
+  }
+
+  @Override
+  protected double distance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    // Algorithm:
+    // (1) If the point is within any of the segments along the path, return that value.
+    // (2) If the point is within any of the segment end circles along the path, return that value.
+    double currentDistance = 0.0;
+    for (PathSegment segment : segments) {
+      double distance = segment.pathDistance(planetModel, distanceStyle, x,y,z);
+      if (distance != Double.MAX_VALUE)
+        return currentDistance + distance;
+      currentDistance += segment.fullPathDistance(distanceStyle);
+    }
+
+    int segmentIndex = 0;
+    currentDistance = 0.0;
+    for (SegmentEndpoint endpoint : endPoints) {
+      double distance = endpoint.pathDistance(distanceStyle, x, y, z);
+      if (distance != Double.MAX_VALUE)
+        return currentDistance + distance;
+      if (segmentIndex < segments.size())
+        currentDistance += segments.get(segmentIndex++).fullPathDistance(distanceStyle);
+    }
+
+    return Double.MAX_VALUE;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    double minDistance = Double.MAX_VALUE;
+    for (final SegmentEndpoint endpoint : endPoints) {
+      final double newDistance = endpoint.outsideDistance(distanceStyle, x,y,z);
+      if (newDistance < minDistance)
+        minDistance = newDistance;
+    }
+    for (final PathSegment segment : segments) {
+      final double newDistance = segment.outsideDistance(planetModel, distanceStyle, x, y, z);
+      if (newDistance < minDistance)
+        minDistance = newDistance;
+    }
+    return minDistance;
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    for (SegmentEndpoint pathPoint : endPoints) {
+      if (pathPoint.isWithin(x, y, z))
+        return true;
+    }
+    for (PathSegment pathSegment : segments) {
+      if (pathSegment.isWithin(x, y, z))
+        return true;
+    }
+    return false;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane plane, final GeoPoint[] notablePoints, final Membership... bounds) {
+    // We look for an intersection with any of the exterior edges of the path.
+    // We also have to look for intersections with the cones described by the endpoints.
+    // Return "true" if any such intersections are found.
+
+    // For plane intersections, the basic idea is to come up with an equation of the line that is
+    // the intersection (if any).  Then, find the intersections with the unit sphere (if any).  If
+    // any of the intersection points are within the bounds, then we've detected an intersection.
+    // Well, sort of.  We can detect intersections also due to overlap of segments with each other.
+    // But that's an edge case and we won't be optimizing for it.
+    //System.err.println(" Looking for intersection of plane "+plane+" with path "+this);
+    for (final SegmentEndpoint pathPoint : endPoints) {
+      if (pathPoint.intersects(planetModel, plane, notablePoints, bounds)) {
+        return true;
+      }
+    }
+
+    for (final PathSegment pathSegment : segments) {
+      if (pathSegment.intersects(planetModel, plane, notablePoints, bounds)) {
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    // For building bounds, order matters.  We want to traverse
+    // never more than 180 degrees longitude at a pop or we risk having the
+    // bounds object get itself inverted.  So do the edges first.
+    for (PathSegment pathSegment : segments) {
+      pathSegment.getBounds(planetModel, bounds);
+    }
+    for (SegmentEndpoint pathPoint : endPoints) {
+      pathPoint.getBounds(planetModel, bounds);
+    }
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoPath))
+      return false;
+    GeoPath p = (GeoPath) o;
+    if (!super.equals(p))
+      return false;
+    if (cutoffAngle != p.cutoffAngle)
+      return false;
+    return points.equals(p.points);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    long temp = Double.doubleToLongBits(cutoffAngle);
+    result = 31 * result + (int) (temp ^ (temp >>> 32));
+    result = 31 * result + points.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoPath: {planetmodel=" + planetModel+", width=" + cutoffAngle + "(" + cutoffAngle * 180.0 / Math.PI + "), points={" + points + "}}";
+  }
+
+  /**
+   * This is precalculated data for segment endpoint.
+   * Note well: This is not necessarily a circle.  There are four cases:
+   * (1) The path consists of a single endpoint.  In this case, we build a simple circle with the proper cutoff offset.
+   * (2) This is the end of a path.  The circle plane must be constructed to go through two supplied points and be perpendicular to a connecting plane.
+   * (2.5) Intersection, but the path on both sides is linear.  We generate a circle, but we use the cutoff planes to limit its influence in the straight line case.
+   * (3) This is an intersection in a path.  We are supplied FOUR planes.  If there are intersections within bounds for both upper and lower, then
+   *    we generate no circle at all.  If there is one intersection only, then we generate a plane that includes that intersection, as well as the remaining
+   *    cutoff plane/edge plane points.
+   */
+  public static class SegmentEndpoint {
+    /** The center point of the endpoint */
+    public final GeoPoint point;
+    /** A plane describing the circle */
+    public final SidedPlane circlePlane;
+    /** Pertinent cutoff planes from adjoining segments */
+    public final Membership[] cutoffPlanes;
+    /** Notable points for this segment endpoint */
+    public final GeoPoint[] notablePoints;
+    /** No notable points from the circle itself */
+    public final static GeoPoint[] circlePoints = new GeoPoint[0];
+    /** Null membership */
+    public final static Membership[] NO_MEMBERSHIP = new Membership[0];
+    
+    /** Base case.  Does nothing at all.
+     */
+    public SegmentEndpoint(final GeoPoint point) {
+      this.point = point;
+      this.circlePlane = null;
+      this.cutoffPlanes = null;
+      this.notablePoints = null;
+    }
+    
+    /** Constructor for case (1).
+     * Generate a simple circle cutoff plane.
+     *@param point is the center point.
+     *@param upperPoint is a point that must be on the circle plane.
+     *@param lowerPoint is another point that must be on the circle plane.
+     */
+    public SegmentEndpoint(final GeoPoint point, final Plane normalPlane, final GeoPoint upperPoint, final GeoPoint lowerPoint) {
+      this.point = point;
+      // Construct a sided plane that goes through the two points and whose normal is in the normalPlane.
+      this.circlePlane = SidedPlane.constructNormalizedPerpendicularSidedPlane(point, normalPlane, upperPoint, lowerPoint);
+      this.cutoffPlanes = NO_MEMBERSHIP;
+      this.notablePoints = circlePoints;
+    }
+    
+    /** Constructor for case (2).
+     * Generate an endpoint, given a single cutoff plane plus upper and lower edge points.
+     *@param point is the center point.
+     *@param cutoffPlane is the plane from the adjoining path segment marking the boundary between this endpoint and that segment.
+     *@param topEdgePoint is a point on the cutoffPlane that should be also on the circle plane.
+     *@param bottomEdgePoint is another point on the cutoffPlane that should be also on the circle plane.
+     */
+    public SegmentEndpoint(final GeoPoint point,
+      final SidedPlane cutoffPlane, final GeoPoint topEdgePoint, final GeoPoint bottomEdgePoint) {
+      this.point = point;
+      this.cutoffPlanes = new Membership[]{new SidedPlane(cutoffPlane)};
+      this.notablePoints = new GeoPoint[]{topEdgePoint, bottomEdgePoint};
+      // To construct the plane, we now just need D, which is simply the negative of the evaluation of the circle normal vector at one of the points.
+      this.circlePlane = SidedPlane.constructNormalizedPerpendicularSidedPlane(point, cutoffPlane, topEdgePoint, bottomEdgePoint);
+    }
+
+    /** Constructor for case (2.5).
+     * Generate an endpoint, given two cutoff planes plus upper and lower edge points.
+     *@param point is the center.
+     *@param cutoffPlane1 is one adjoining path segment cutoff plane.
+     *@param cutoffPlane2 is another adjoining path segment cutoff plane.
+     *@param topEdgePoint is a point on the cutoffPlane that should be also on the circle plane.
+     *@param bottomEdgePoint is another point on the cutoffPlane that should be also on the circle plane.
+     */
+    public SegmentEndpoint(final GeoPoint point,
+      final SidedPlane cutoffPlane1, final SidedPlane cutoffPlane2, final GeoPoint topEdgePoint, final GeoPoint bottomEdgePoint) {
+      this.point = point;
+      this.cutoffPlanes = new Membership[]{new SidedPlane(cutoffPlane1), new SidedPlane(cutoffPlane2)};
+      this.notablePoints = new GeoPoint[]{topEdgePoint, bottomEdgePoint};
+      // To construct the plane, we now just need D, which is simply the negative of the evaluation of the circle normal vector at one of the points.
+      this.circlePlane = SidedPlane.constructNormalizedPerpendicularSidedPlane(point, cutoffPlane1, topEdgePoint, bottomEdgePoint);
+    }
+    
+    /** Constructor for case (3).
+     * Generate an endpoint for an intersection, given four points.
+     *@param point is the center.
+     *@param prevCutoffPlane is the previous adjoining segment cutoff plane.
+     *@param nextCutoffPlane is the next path segment cutoff plane.
+     *@param notCand2Point is a point NOT on candidate2.
+     *@param notCand1Point is a point NOT on candidate1.
+     *@param notCand3Point is a point NOT on candidate3.
+     *@param notCand4Point is a point NOT on candidate4.
+     *@param candidate1 one of four candidate circle planes.
+     *@param candidate2 one of four candidate circle planes.
+     *@param candidate3 one of four candidate circle planes.
+     *@param candidate4 one of four candidate circle planes.
+     */
+    public SegmentEndpoint(final GeoPoint point,
+      final SidedPlane prevCutoffPlane, final SidedPlane nextCutoffPlane,
+      final GeoPoint notCand2Point, final GeoPoint notCand1Point,
+      final GeoPoint notCand3Point, final GeoPoint notCand4Point,
+      final SidedPlane candidate1, final SidedPlane candidate2, final SidedPlane candidate3, final SidedPlane candidate4) {
+      // Note: What we really need is a single plane that goes through all four points.
+      // Since that's not possible in the ellipsoid case (because three points determine a plane, not four), we
+      // need an approximation that at least creates a boundary that has no interruptions.
+      // There are three obvious choices for the third point: either (a) one of the two remaining points, or (b) the top or bottom edge
+      // intersection point.  (a) has no guarantee of continuity, while (b) is capable of producing something very far from a circle if
+      // the angle between segments is acute.
+      // The solution is to look for the side (top or bottom) that has an intersection within the shape.  We use the two points from
+      // the opposite side to determine the plane, AND we pick the third to be either of the two points on the intersecting side
+      // PROVIDED that the other point is within the final circle we come up with.
+      this.point = point;
+      
+      // We construct four separate planes, and evaluate which one includes all interior points with least overlap
+      // (Constructed beforehand because we need them for degeneracy check)
+
+      final boolean cand1IsOtherWithin = candidate1!=null?candidate1.isWithin(notCand1Point):false;
+      final boolean cand2IsOtherWithin = candidate2!=null?candidate2.isWithin(notCand2Point):false;
+      final boolean cand3IsOtherWithin = candidate3!=null?candidate3.isWithin(notCand3Point):false;
+      final boolean cand4IsOtherWithin = candidate4!=null?candidate4.isWithin(notCand4Point):false;
+      
+      if (cand1IsOtherWithin && cand2IsOtherWithin && cand3IsOtherWithin && cand4IsOtherWithin) {
+        // The only way we should see both within is if all four points are coplanar.  In that case, we default to the simplest treatment.
+        this.circlePlane = candidate1;  // doesn't matter which
+        this.notablePoints = new GeoPoint[]{notCand2Point, notCand3Point, notCand1Point, notCand4Point};
+        this.cutoffPlanes = new Membership[]{new SidedPlane(prevCutoffPlane), new SidedPlane(nextCutoffPlane)};
+      } else if (cand1IsOtherWithin) {
+        // Use candidate1, and DON'T include prevCutoffPlane in the cutoff planes list
+        this.circlePlane = candidate1;
+        this.notablePoints = new GeoPoint[]{notCand2Point, notCand3Point, notCand4Point};
+        this.cutoffPlanes = new Membership[]{new SidedPlane(nextCutoffPlane)};
+      } else if (cand2IsOtherWithin) {
+        // Use candidate2
+        this.circlePlane = candidate2;
+        this.notablePoints = new GeoPoint[]{notCand3Point, notCand4Point, notCand1Point};
+        this.cutoffPlanes = new Membership[]{new SidedPlane(nextCutoffPlane)};
+      } else if (cand3IsOtherWithin) {
+        this.circlePlane = candidate3;
+        this.notablePoints = new GeoPoint[]{notCand4Point, notCand1Point, notCand2Point};
+        this.cutoffPlanes = new Membership[]{new SidedPlane(prevCutoffPlane)};
+      } else if (cand4IsOtherWithin) {
+        this.circlePlane = candidate4;
+        this.notablePoints = new GeoPoint[]{notCand1Point, notCand2Point, notCand3Point};
+        this.cutoffPlanes = new Membership[]{new SidedPlane(prevCutoffPlane)};
+      } else {
+        // dunno what happened
+        throw new RuntimeException("Couldn't come up with a plane through three points that included the fourth");
+      }
+    }
+
+    /** Check if point is within this endpoint.
+     *@param point is the point.
+     *@return true of within.
+     */
+    public boolean isWithin(final Vector point) {
+      if (circlePlane == null)
+        return false;
+      if (!circlePlane.isWithin(point))
+        return false;
+      for (final Membership m : cutoffPlanes) {
+        if (!m.isWithin(point)) {
+          return false;
+        }
+      }
+      return true;
+    }
+
+    /** Check if point is within this endpoint.
+     *@param x is the point x.
+     *@param y is the point y.
+     *@param z is the point z.
+     *@return true of within.
+     */
+    public boolean isWithin(final double x, final double y, final double z) {
+      if (circlePlane == null)
+        return false;
+      if (!circlePlane.isWithin(x, y, z))
+        return false;
+      for (final Membership m : cutoffPlanes) {
+        if (!m.isWithin(x,y,z)) {
+          return false;
+        }
+      }
+      return true;
+    }
+
+    /** Compute interior path distance.
+     *@param distanceStyle is the distance style.
+     *@param x is the point x.
+     *@param y is the point y.
+     *@param z is the point z.
+     *@return the distance metric.
+     */
+    public double pathDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+      if (!isWithin(x,y,z))
+        return Double.MAX_VALUE;
+      return distanceStyle.computeDistance(this.point, x, y, z);
+    }
+
+    /** Compute external distance.
+     *@param distanceStyle is the distance style.
+     *@param x is the point x.
+     *@param y is the point y.
+     *@param z is the point z.
+     *@return the distance metric.
+     */
+    public double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+      return distanceStyle.computeDistance(this.point, x, y, z);
+    }
+
+    /** Determine if this endpoint intersects a specified plane.
+     *@param planetModel is the planet model.
+     *@param p is the plane.
+     *@param notablePoints are the points associated with the plane.
+     *@param bounds are any bounds which the intersection must lie within.
+     *@return true if there is a matching intersection.
+     */
+    public boolean intersects(final PlanetModel planetModel, final Plane p, final GeoPoint[] notablePoints, final Membership[] bounds) {
+      //System.err.println("  looking for intersection between plane "+p+" and circle "+circlePlane+" on proper side of "+cutoffPlanes+" within "+bounds);
+      if (circlePlane == null)
+        return false;
+      return circlePlane.intersects(planetModel, p, notablePoints, this.notablePoints, bounds, this.cutoffPlanes);
+    }
+
+    /** Get the bounds for a segment endpoint.
+     *@param planetModel is the planet model.
+     *@param bounds are the bounds to be modified.
+     */
+    public void getBounds(final PlanetModel planetModel, Bounds bounds) {
+      bounds.addPoint(point);
+      if (circlePlane == null)
+        return;
+      bounds.addPlane(planetModel, circlePlane);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      if (!(o instanceof SegmentEndpoint))
+        return false;
+      SegmentEndpoint other = (SegmentEndpoint) o;
+      return point.equals(other.point);
+    }
+
+    @Override
+    public int hashCode() {
+      return point.hashCode();
+    }
+
+    @Override
+    public String toString() {
+      return point.toString();
+    }
+  }
+
+  /**
+   * This is the pre-calculated data for a path segment.
+   */
+  public static class PathSegment {
+    /** Starting point of the segment */
+    public final GeoPoint start;
+    /** End point of the segment */
+    public final GeoPoint end;
+    /** Place to keep any complete segment distances we've calculated so far */
+    public final Map<DistanceStyle,Double> fullDistanceCache = new HashMap<DistanceStyle,Double>();
+    /** Normalized plane connecting the two points and going through world center */
+    public final Plane normalizedConnectingPlane;
+    /** Cutoff plane parallel to connecting plane representing one side of the path segment */
+    public final SidedPlane upperConnectingPlane;
+    /** Cutoff plane parallel to connecting plane representing the other side of the path segment */
+    public final SidedPlane lowerConnectingPlane;
+    /** Plane going through the center and start point, marking the start edge of the segment */
+    public final SidedPlane startCutoffPlane;
+    /** Plane going through the center and end point, marking the end edge of the segment */
+    public final SidedPlane endCutoffPlane;
+    /** Upper right hand corner of segment */
+    public final GeoPoint URHC;
+    /** Lower right hand corner of segment */
+    public final GeoPoint LRHC;
+    /** Upper left hand corner of segment */
+    public final GeoPoint ULHC;
+    /** Lower left hand corner of segment */
+    public final GeoPoint LLHC;
+    /** Notable points for the upper connecting plane */
+    public final GeoPoint[] upperConnectingPlanePoints;
+    /** Notable points for the lower connecting plane */
+    public final GeoPoint[] lowerConnectingPlanePoints;
+    /** Notable points for the start cutoff plane */
+    public final GeoPoint[] startCutoffPlanePoints;
+    /** Notable points for the end cutoff plane */
+    public final GeoPoint[] endCutoffPlanePoints;
+
+    /** Construct a path segment.
+     *@param planetModel is the planet model.
+     *@param start is the starting point.
+     *@param end is the ending point.
+     *@param normalizedConnectingPlane is the connecting plane.
+     *@param planeBoundingOffset is the linear offset from the connecting plane to either side.
+     */
+    public PathSegment(final PlanetModel planetModel, final GeoPoint start, final GeoPoint end,
+      final Plane normalizedConnectingPlane, final double planeBoundingOffset) {
+      this.start = start;
+      this.end = end;
+      this.normalizedConnectingPlane = normalizedConnectingPlane;
+        
+      // Either start or end should be on the correct side
+      upperConnectingPlane = new SidedPlane(start, normalizedConnectingPlane, -planeBoundingOffset);
+      lowerConnectingPlane = new SidedPlane(start, normalizedConnectingPlane, planeBoundingOffset);
+      // Cutoff planes use opposite endpoints as correct side examples
+      startCutoffPlane = new SidedPlane(end, normalizedConnectingPlane, start);
+      endCutoffPlane = new SidedPlane(start, normalizedConnectingPlane, end);
+      final Membership[] upperSide = new Membership[]{upperConnectingPlane};
+      final Membership[] lowerSide = new Membership[]{lowerConnectingPlane};
+      final Membership[] startSide = new Membership[]{startCutoffPlane};
+      final Membership[] endSide = new Membership[]{endCutoffPlane};
+      GeoPoint[] points;
+      points = upperConnectingPlane.findIntersections(planetModel, startCutoffPlane, lowerSide, endSide);
+      if (points.length == 0) {
+        throw new IllegalArgumentException("Some segment boundary points are off the ellipsoid; path too wide");
+      }
+      this.ULHC = points[0];
+      points = upperConnectingPlane.findIntersections(planetModel, endCutoffPlane, lowerSide, startSide);
+      if (points.length == 0) {
+        throw new IllegalArgumentException("Some segment boundary points are off the ellipsoid; path too wide");
+      }
+      this.URHC = points[0];
+      points = lowerConnectingPlane.findIntersections(planetModel, startCutoffPlane, upperSide, endSide);
+      if (points.length == 0) {
+        throw new IllegalArgumentException("Some segment boundary points are off the ellipsoid; path too wide");
+      }
+      this.LLHC = points[0];
+      points = lowerConnectingPlane.findIntersections(planetModel, endCutoffPlane, upperSide, startSide);
+      if (points.length == 0) {
+        throw new IllegalArgumentException("Some segment boundary points are off the ellipsoid; path too wide");
+      }
+      this.LRHC = points[0];
+      upperConnectingPlanePoints = new GeoPoint[]{ULHC, URHC};
+      lowerConnectingPlanePoints = new GeoPoint[]{LLHC, LRHC};
+      startCutoffPlanePoints = new GeoPoint[]{ULHC, LLHC};
+      endCutoffPlanePoints = new GeoPoint[]{URHC, LRHC};
+    }
+
+    /** Compute the full distance along this path segment.
+     *@param distanceStyle is the distance style.
+     *@return the distance metric.
+     */
+    public double fullPathDistance(final DistanceStyle distanceStyle) {
+      synchronized (fullDistanceCache) {
+        Double dist = fullDistanceCache.get(distanceStyle);
+        if (dist == null) {
+          dist = new Double(distanceStyle.computeDistance(start, end.x, end.y, end.z));
+          fullDistanceCache.put(distanceStyle, dist);
+        }
+        return dist.doubleValue();
+      }
+    }
+  
+    /** Check if point is within this segment.
+     *@param point is the point.
+     *@return true of within.
+     */
+    public boolean isWithin(final Vector point) {
+      return startCutoffPlane.isWithin(point) &&
+          endCutoffPlane.isWithin(point) &&
+          upperConnectingPlane.isWithin(point) &&
+          lowerConnectingPlane.isWithin(point);
+    }
+
+    /** Check if point is within this segment.
+     *@param x is the point x.
+     *@param y is the point y.
+     *@param z is the point z.
+     *@return true of within.
+     */
+    public boolean isWithin(final double x, final double y, final double z) {
+      return startCutoffPlane.isWithin(x, y, z) &&
+          endCutoffPlane.isWithin(x, y, z) &&
+          upperConnectingPlane.isWithin(x, y, z) &&
+          lowerConnectingPlane.isWithin(x, y, z);
+    }
+
+    /** Compute interior path distance.
+     *@param planetModel is the planet model.
+     *@param distanceStyle is the distance style.
+     *@param x is the point x.
+     *@param y is the point y.
+     *@param z is the point z.
+     *@return the distance metric.
+     */
+    public double pathDistance(final PlanetModel planetModel, final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+      if (!isWithin(x,y,z))
+        return Double.MAX_VALUE;
+
+      // (1) Compute normalizedPerpPlane.  If degenerate, then return point distance from start to point.
+      // Want no allocations or expensive operations!  so we do this the hard way
+      final double perpX = normalizedConnectingPlane.y * z - normalizedConnectingPlane.z * y;
+      final double perpY = normalizedConnectingPlane.z * x - normalizedConnectingPlane.x * z;
+      final double perpZ = normalizedConnectingPlane.x * y - normalizedConnectingPlane.y * x;
+      final double magnitude = Math.sqrt(perpX * perpX + perpY * perpY + perpZ * perpZ);
+      if (Math.abs(magnitude) < Vector.MINIMUM_RESOLUTION)
+        return distanceStyle.computeDistance(start, x,y,z);
+      final double normFactor = 1.0/magnitude;
+      final Plane normalizedPerpPlane = new Plane(perpX * normFactor, perpY * normFactor, perpZ * normFactor, 0.0);
+      
+      // Old computation: too expensive, because it calculates the intersection point twice.
+      //return distanceStyle.computeDistance(planetModel, normalizedConnectingPlane, x, y, z, startCutoffPlane, endCutoffPlane) +
+      //  distanceStyle.computeDistance(planetModel, normalizedPerpPlane, start.x, start.y, start.z, upperConnectingPlane, lowerConnectingPlane);
+
+      final GeoPoint[] intersectionPoints = normalizedConnectingPlane.findIntersections(planetModel, normalizedPerpPlane);
+      GeoPoint thePoint;
+      if (intersectionPoints.length == 0)
+        throw new RuntimeException("Can't find world intersection for point x="+x+" y="+y+" z="+z);
+      else if (intersectionPoints.length == 1)
+        thePoint = intersectionPoints[0];
+      else {
+        if (startCutoffPlane.isWithin(intersectionPoints[0]) && endCutoffPlane.isWithin(intersectionPoints[0]))
+          thePoint = intersectionPoints[0];
+        else if (startCutoffPlane.isWithin(intersectionPoints[1]) && endCutoffPlane.isWithin(intersectionPoints[1]))
+          thePoint = intersectionPoints[1];
+        else
+          throw new RuntimeException("Can't find world intersection for point x="+x+" y="+y+" z="+z);
+      }
+      return distanceStyle.computeDistance(thePoint, x, y, z) + distanceStyle.computeDistance(start, thePoint.x, thePoint.y, thePoint.z);
+    }
+
+    /** Compute external distance.
+     *@param planetModel is the planet model.
+     *@param distanceStyle is the distance style.
+     *@param x is the point x.
+     *@param y is the point y.
+     *@param z is the point z.
+     *@return the distance metric.
+     */
+    public double outsideDistance(final PlanetModel planetModel, final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+      final double upperDistance = distanceStyle.computeDistance(planetModel, upperConnectingPlane, x,y,z, lowerConnectingPlane, startCutoffPlane, endCutoffPlane);
+      final double lowerDistance = distanceStyle.computeDistance(planetModel, lowerConnectingPlane, x,y,z, upperConnectingPlane, startCutoffPlane, endCutoffPlane);
+      final double startDistance = distanceStyle.computeDistance(planetModel, startCutoffPlane, x,y,z, endCutoffPlane, lowerConnectingPlane, upperConnectingPlane);
+      final double endDistance = distanceStyle.computeDistance(planetModel, endCutoffPlane, x,y,z, startCutoffPlane, lowerConnectingPlane, upperConnectingPlane);
+      final double ULHCDistance = distanceStyle.computeDistance(ULHC, x,y,z);
+      final double URHCDistance = distanceStyle.computeDistance(URHC, x,y,z);
+      final double LLHCDistance = distanceStyle.computeDistance(LLHC, x,y,z);
+      final double LRHCDistance = distanceStyle.computeDistance(LRHC, x,y,z);
+      return Math.min(
+        Math.min(
+          Math.min(upperDistance,lowerDistance),
+          Math.min(startDistance,endDistance)),
+        Math.min(
+          Math.min(ULHCDistance, URHCDistance),
+          Math.min(LLHCDistance, LRHCDistance)));
+    }
+
+    /** Determine if this endpoint intersects a specified plane.
+     *@param planetModel is the planet model.
+     *@param p is the plane.
+     *@param notablePoints are the points associated with the plane.
+     *@param bounds are any bounds which the intersection must lie within.
+     *@return true if there is a matching intersection.
+     */
+    public boolean intersects(final PlanetModel planetModel, final Plane p, final GeoPoint[] notablePoints, final Membership[] bounds) {
+      return upperConnectingPlane.intersects(planetModel, p, notablePoints, upperConnectingPlanePoints, bounds, lowerConnectingPlane, startCutoffPlane, endCutoffPlane) ||
+          lowerConnectingPlane.intersects(planetModel, p, notablePoints, lowerConnectingPlanePoints, bounds, upperConnectingPlane, startCutoffPlane, endCutoffPlane);
+    }
+
+    /** Get the bounds for a segment endpoint.
+     *@param planetModel is the planet model.
+     *@param bounds are the bounds to be modified.
+     */
+    public void getBounds(final PlanetModel planetModel, Bounds bounds) {
+      // We need to do all bounding planes as well as corner points
+      bounds.addPoint(start).addPoint(end).addPoint(ULHC).addPoint(URHC).addPoint(LRHC).addPoint(LLHC);
+      bounds.addPlane(planetModel, upperConnectingPlane, lowerConnectingPlane, startCutoffPlane, endCutoffPlane);
+      bounds.addPlane(planetModel, lowerConnectingPlane, upperConnectingPlane, startCutoffPlane, endCutoffPlane);
+      bounds.addPlane(planetModel, startCutoffPlane, endCutoffPlane, upperConnectingPlane, lowerConnectingPlane);
+      bounds.addPlane(planetModel, endCutoffPlane, startCutoffPlane, upperConnectingPlane, lowerConnectingPlane);
+    }
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPoint.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPoint.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPoint.java
new file mode 100755
index 0000000..31ab0aa
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPoint.java
@@ -0,0 +1,193 @@
+/*
+ * 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.spatial3d.geom;
+    
+/**
+ * This class represents a point on the surface of a sphere or ellipsoid.
+ *
+ * @lucene.experimental
+ */
+public class GeoPoint extends Vector {
+  
+  // By making lazily-evaluated variables be "volatile", we guarantee atomicity when they
+  // are updated.  This is necessary if we are using these classes in a multi-thread fashion,
+  // because we don't try to synchronize for the lazy computation.
+  
+  /** This is the lazily-evaluated magnitude.  Some constructors include it, but others don't, and
+   * we try not to create extra computation by always computing it.  Does not need to be
+   * synchronized for thread safety, because depends wholly on immutable variables of this class. */
+  protected volatile double magnitude = Double.NEGATIVE_INFINITY;
+  /** Lazily-evaluated latitude.  Does not need to be
+   * synchronized for thread safety, because depends wholly on immutable variables of this class.  */
+  protected volatile double latitude = Double.NEGATIVE_INFINITY;
+  /** Lazily-evaluated longitude.   Does not need to be
+   * synchronized for thread safety, because depends wholly on immutable variables of this class.  */
+  protected volatile double longitude = Double.NEGATIVE_INFINITY;
+
+  /** Construct a GeoPoint from the trig functions of a lat and lon pair.
+   * @param planetModel is the planetModel to put the point on.
+   * @param sinLat is the sin of the latitude.
+   * @param sinLon is the sin of the longitude.
+   * @param cosLat is the cos of the latitude.
+   * @param cosLon is the cos of the longitude.
+   * @param lat is the latitude.
+   * @param lon is the longitude.
+   */
+  public GeoPoint(final PlanetModel planetModel, final double sinLat, final double sinLon, final double cosLat, final double cosLon, final double lat, final double lon) {
+    this(computeDesiredEllipsoidMagnitude(planetModel, cosLat * cosLon, cosLat * sinLon, sinLat),
+      cosLat * cosLon, cosLat * sinLon, sinLat, lat, lon);
+  }
+  
+  /** Construct a GeoPoint from the trig functions of a lat and lon pair.
+   * @param planetModel is the planetModel to put the point on.
+   * @param sinLat is the sin of the latitude.
+   * @param sinLon is the sin of the longitude.
+   * @param cosLat is the cos of the latitude.
+   * @param cosLon is the cos of the longitude.
+   */
+  public GeoPoint(final PlanetModel planetModel, final double sinLat, final double sinLon, final double cosLat, final double cosLon) {
+    this(computeDesiredEllipsoidMagnitude(planetModel, cosLat * cosLon, cosLat * sinLon, sinLat),
+      cosLat * cosLon, cosLat * sinLon, sinLat);
+  }
+
+  /** Construct a GeoPoint from a latitude/longitude pair.
+   * @param planetModel is the planetModel to put the point on.
+   * @param lat is the latitude.
+   * @param lon is the longitude.
+   */
+  public GeoPoint(final PlanetModel planetModel, final double lat, final double lon) {
+    this(planetModel, Math.sin(lat), Math.sin(lon), Math.cos(lat), Math.cos(lon), lat, lon);
+  }
+  
+  /** Construct a GeoPoint from a unit (x,y,z) vector and a magnitude.
+   * @param magnitude is the desired magnitude, provided to put the point on the ellipsoid.
+   * @param x is the unit x value.
+   * @param y is the unit y value.
+   * @param z is the unit z value.
+   * @param lat is the latitude.
+   * @param lon is the longitude.
+   */
+  public GeoPoint(final double magnitude, final double x, final double y, final double z, double lat, double lon) {
+    super(x * magnitude, y * magnitude, z * magnitude);
+    this.magnitude = magnitude;
+    if (lat > Math.PI * 0.5 || lat < -Math.PI * 0.5) {
+      throw new IllegalArgumentException("Latitude " + lat + " is out of range: must range from -Math.PI/2 to Math.PI/2");
+    }
+    if (lon < -Math.PI || lon > Math.PI) {
+      throw new IllegalArgumentException("Longitude " + lon + " is out of range: must range from -Math.PI to Math.PI");
+    }
+    this.latitude = lat;
+    this.longitude = lon;
+  }
+
+  /** Construct a GeoPoint from a unit (x,y,z) vector and a magnitude.
+   * @param magnitude is the desired magnitude, provided to put the point on the ellipsoid.
+   * @param x is the unit x value.
+   * @param y is the unit y value.
+   * @param z is the unit z value.
+   */
+  public GeoPoint(final double magnitude, final double x, final double y, final double z) {
+    super(x * magnitude, y * magnitude, z * magnitude);
+    this.magnitude = magnitude;
+  }
+  
+  /** Construct a GeoPoint from an (x,y,z) value.
+   * The (x,y,z) tuple must be on the desired ellipsoid.
+   * @param x is the ellipsoid point x value.
+   * @param y is the ellipsoid point y value.
+   * @param z is the ellipsoid point z value.
+   */
+  public GeoPoint(final double x, final double y, final double z) {
+    super(x, y, z);
+  }
+
+  /** Compute an arc distance between two points.
+   * Note: this is an angular distance, and not a surface distance, and is therefore independent of planet model.
+   * For surface distance, see {@link PlanetModel#surfaceDistance(GeoPoint, GeoPoint)}
+   * @param v is the second point.
+   * @return the angle, in radians, between the two points.
+   */
+  public double arcDistance(final GeoPoint v) {
+    return Tools.safeAcos(dotProduct(v)/(magnitude() * v.magnitude()));
+  }
+
+  /** Compute an arc distance between two points.
+   * @param x is the x part of the second point.
+   * @param y is the y part of the second point.
+   * @param z is the z part of the second point.
+   * @return the angle, in radians, between the two points.
+   */
+  public double arcDistance(final double x, final double y, final double z) {
+    return Tools.safeAcos(dotProduct(x,y,z)/(magnitude() * Vector.magnitude(x,y,z)));
+  }
+
+  /** Compute the latitude for the point.
+   * @return the latitude.
+   */
+  public double getLatitude() {
+    double lat = this.latitude;//volatile-read once
+    if (lat == Double.NEGATIVE_INFINITY)
+      this.latitude = lat = Math.asin(z / magnitude());
+    return lat;
+  }
+  
+  /** Compute the longitude for the point.
+   * @return the longitude value.  Uses 0.0 if there is no computable longitude.
+   */
+  public double getLongitude() {
+    double lon = this.longitude;//volatile-read once
+    if (lon == Double.NEGATIVE_INFINITY) {
+      if (Math.abs(x) < MINIMUM_RESOLUTION && Math.abs(y) < MINIMUM_RESOLUTION)
+        this.longitude = lon = 0.0;
+      else
+        this.longitude = lon = Math.atan2(y,x);
+    }
+    return lon;
+  }
+  
+  /** Compute the linear magnitude of the point.
+   * @return the magnitude.
+   */
+  @Override
+  public double magnitude() {
+    double mag = this.magnitude;//volatile-read once
+    if (mag == Double.NEGATIVE_INFINITY) {
+      this.magnitude = mag = super.magnitude();
+    }
+    return mag;
+  }
+  
+  /** Compute whether point matches another.
+   *@param x is the x value
+   *@param y is the y value
+   *@param z is the z value
+   *@return true if the same.
+   */
+  public boolean isIdentical(final double x, final double y, final double z) {
+    return Math.abs(this.x - x) < MINIMUM_RESOLUTION &&
+      Math.abs(this.y - y) < MINIMUM_RESOLUTION &&
+      Math.abs(this.z - z) < MINIMUM_RESOLUTION;
+  }
+  
+  @Override
+  public String toString() {
+    if (this.longitude == Double.NEGATIVE_INFINITY) {
+      return super.toString();
+    }
+    return "[lat="+getLatitude()+", lon="+getLongitude()+"]";
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygon.java
new file mode 100644
index 0000000..742bdf8
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygon.java
@@ -0,0 +1,26 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * GeoPolygon interface description.
+ *
+ * @lucene.experimental
+ */
+public interface GeoPolygon extends GeoMembershipShape {
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java
new file mode 100755
index 0000000..8ee4290
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java
@@ -0,0 +1,187 @@
+/*
+ * 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.spatial3d.geom;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.List;
+
+/**
+ * Class which constructs a GeoMembershipShape representing an arbitrary polygon.
+ *
+ * @lucene.experimental
+ */
+public class GeoPolygonFactory {
+  private GeoPolygonFactory() {
+  }
+
+  /**
+   * Create a GeoMembershipShape of the right kind given the specified bounds.
+   *
+   * @param pointList        is a list of the GeoPoints to build an arbitrary polygon out of.
+   * @param convexPointIndex is the index of a single convex point whose conformation with
+   *                         its neighbors determines inside/outside for the entire polygon.
+   * @return a GeoPolygon corresponding to what was specified.
+   */
+  public static GeoPolygon makeGeoPolygon(final PlanetModel planetModel, final List<GeoPoint> pointList, final int convexPointIndex) {
+    // The basic operation uses a set of points, two points determining one particular edge, and a sided plane
+    // describing membership.
+    return buildPolygonShape(planetModel, pointList, convexPointIndex, getLegalIndex(convexPointIndex + 1, pointList.size()),
+        new SidedPlane(pointList.get(getLegalIndex(convexPointIndex - 1, pointList.size())),
+            pointList.get(convexPointIndex), pointList.get(getLegalIndex(convexPointIndex + 1, pointList.size()))),
+        false);
+  }
+
+  /** Build a GeoMembershipShape given points, starting edge, and whether starting edge is internal or not.
+   * @param pointsList        is a list of the GeoPoints to build an arbitrary polygon out of.
+   * @param startPointIndex is one of the points constituting the starting edge.
+   * @param endPointIndex is another of the points constituting the starting edge.
+   * @param startingEdge is the plane describing the starting edge.
+   * @param isInternalEdge is true if the specified edge is an internal one.
+   * @return a GeoMembershipShape corresponding to what was specified.
+   */
+  public static GeoPolygon buildPolygonShape(final PlanetModel planetModel, final List<GeoPoint> pointsList, final int startPointIndex, final int endPointIndex, final SidedPlane startingEdge, final boolean isInternalEdge) {
+    // Algorithm as follows:
+    // Start with sided edge.  Go through all points in some order.  For each new point, determine if the point is within all edges considered so far.
+    // If not, put it into a list of points for recursion.  If it is within, add new edge and keep going.
+    // Once we detect a point that is within, if there are points put aside for recursion, then call recursively.
+
+    // Current composite.  This is what we'll actually be returning.
+    final GeoCompositePolygon rval = new GeoCompositePolygon();
+
+    final List<GeoPoint> recursionList = new ArrayList<GeoPoint>();
+    final List<GeoPoint> currentList = new ArrayList<GeoPoint>();
+    final BitSet internalEdgeList = new BitSet();
+    final List<SidedPlane> currentPlanes = new ArrayList<SidedPlane>();
+
+    // Initialize the current list and current planes
+    currentList.add(pointsList.get(startPointIndex));
+    currentList.add(pointsList.get(endPointIndex));
+    internalEdgeList.set(currentPlanes.size(), isInternalEdge);
+    currentPlanes.add(startingEdge);
+
+    // Now, scan all remaining points, in order.  We'll use an index and just add to it.
+    for (int i = 0; i < pointsList.size() - 2; i++) {
+      GeoPoint newPoint = pointsList.get(getLegalIndex(i + endPointIndex + 1, pointsList.size()));
+      if (isWithin(newPoint, currentPlanes)) {
+        // Construct a sided plane based on the last two points, and the previous point
+        SidedPlane newBoundary = new SidedPlane(currentList.get(currentList.size() - 2), newPoint, currentList.get(currentList.size() - 1));
+        // Construct a sided plane based on the return trip
+        SidedPlane returnBoundary = new SidedPlane(currentList.get(currentList.size() - 1), currentList.get(0), newPoint);
+        // Verify that none of the points beyond the new point in the list are inside the polygon we'd
+        // be creating if we stopped making the current polygon right now.
+        boolean pointInside = false;
+        for (int j = i + 1; j < pointsList.size() - 2; j++) {
+          GeoPoint checkPoint = pointsList.get(getLegalIndex(j + endPointIndex + 1, pointsList.size()));
+          boolean isInside = true;
+          if (isInside && !newBoundary.isWithin(checkPoint))
+            isInside = false;
+          if (isInside && !returnBoundary.isWithin(checkPoint))
+            isInside = false;
+          if (isInside) {
+            for (SidedPlane plane : currentPlanes) {
+              if (!plane.isWithin(checkPoint)) {
+                isInside = false;
+                break;
+              }
+            }
+          }
+          if (isInside) {
+            pointInside = true;
+            break;
+          }
+        }
+        if (!pointInside) {
+          // Any excluded points?
+          boolean isInternalBoundary = recursionList.size() > 0;
+          if (isInternalBoundary) {
+            // Handle exclusion
+            recursionList.add(newPoint);
+            recursionList.add(currentList.get(currentList.size() - 1));
+            if (recursionList.size() == pointsList.size()) {
+              // We are trying to recurse with a list the same size as the one we started with.
+              // Clearly, the polygon cannot be constructed
+              throw new IllegalArgumentException("Polygon is illegal; cannot be decomposed into convex parts");
+            }
+            // We want the other side for the recursion
+            SidedPlane otherSideNewBoundary = new SidedPlane(newBoundary);
+            rval.addShape(buildPolygonShape(planetModel, recursionList, recursionList.size() - 2, recursionList.size() - 1, otherSideNewBoundary, true));
+            recursionList.clear();
+          }
+          currentList.add(newPoint);
+          internalEdgeList.set(currentPlanes.size(), isInternalBoundary);
+          currentPlanes.add(newBoundary);
+        } else {
+          recursionList.add(newPoint);
+        }
+      } else {
+        recursionList.add(newPoint);
+      }
+    }
+
+    boolean returnEdgeInternalBoundary = recursionList.size() > 0;
+    if (returnEdgeInternalBoundary) {
+      // The last step back to the start point had a recursion, so take care of that before we complete our work
+      recursionList.add(currentList.get(0));
+      recursionList.add(currentList.get(currentList.size() - 1));
+      if (recursionList.size() == pointsList.size()) {
+        // We are trying to recurse with a list the same size as the one we started with.
+        // Clearly, the polygon cannot be constructed
+        throw new IllegalArgumentException("Polygon is illegal; cannot be decomposed into convex parts");
+      }
+      // Construct a sided plane based on these two points, and the previous point
+      SidedPlane newBoundary = new SidedPlane(currentList.get(currentList.size() - 2), currentList.get(0), currentList.get(currentList.size() - 1));
+      // We want the other side for the recursion
+      SidedPlane otherSideNewBoundary = new SidedPlane(newBoundary);
+      rval.addShape(buildPolygonShape(planetModel, recursionList, recursionList.size() - 2, recursionList.size() - 1, otherSideNewBoundary, true));
+      recursionList.clear();
+    }
+    // Now, add in the current shape.
+    rval.addShape(new GeoConvexPolygon(planetModel, currentList, internalEdgeList, returnEdgeInternalBoundary));
+    //System.out.println("Done creating polygon");
+    return rval;
+  }
+
+  /** Check if a point is within a described list of planes.
+   *@param newPoint is the point. 
+   *@param currentPlanes is the list of planes.
+   *@return true if within.
+   */
+  protected static boolean isWithin(final GeoPoint newPoint, final List<SidedPlane> currentPlanes) {
+    for (SidedPlane p : currentPlanes) {
+      if (!p.isWithin(newPoint))
+        return false;
+    }
+    return true;
+  }
+
+  /** Convert raw point index into valid array position.
+   *@param index is the array index.
+   *@param size is the array size.
+   *@return an updated index.
+   */
+  protected static int getLegalIndex(int index, int size) {
+    while (index < 0) {
+      index += size;
+    }
+    while (index >= size) {
+      index -= size;
+    }
+    return index;
+  }
+
+}


[16/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 0093e26)

Posted by ds...@apache.org.
LUCENE-7056: Geo3D package re-org
(cherry picked from commit 0093e26)


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/3a31a8c7
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/3a31a8c7
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/3a31a8c7

Branch: refs/heads/branch_6x
Commit: 3a31a8c7686b27e90f9683c4d3a0cdd2e89d3e91
Parents: d7ee7c6
Author: David Smiley <ds...@apache.org>
Authored: Mon Mar 7 17:29:46 2016 -0500
Committer: David Smiley <ds...@apache.org>
Committed: Mon Mar 7 20:06:05 2016 -0500

----------------------------------------------------------------------
 lucene/CHANGES.txt                              |    2 +
 .../lucene/spatial/spatial4j/Geo3dShape.java    |   12 +-
 .../lucene/spatial/spatial4j/Geo3dRptTest.java  |   14 +-
 .../Geo3dShapeRectRelationTestCase.java         |   18 +-
 .../Geo3dShapeSphereModelRectRelationTest.java  |   16 +-
 .../Geo3dShapeWGS84ModelRectRelationTest.java   |   16 +-
 .../spatial/spatial4j/geo3d/GeoPointTest.java   |   80 -
 .../org/apache/lucene/geo3d/ArcDistance.java    |   56 -
 .../apache/lucene/geo3d/BasePlanetObject.java   |   57 -
 .../org/apache/lucene/geo3d/BaseXYZSolid.java   |  167 --
 .../java/org/apache/lucene/geo3d/Bounds.java    |  113 --
 .../org/apache/lucene/geo3d/DistanceStyle.java  |   83 -
 .../org/apache/lucene/geo3d/Geo3DPoint.java     |  112 --
 .../java/org/apache/lucene/geo3d/Geo3DUtil.java |   59 -
 .../java/org/apache/lucene/geo3d/GeoArea.java   |   67 -
 .../org/apache/lucene/geo3d/GeoAreaFactory.java |   55 -
 .../java/org/apache/lucene/geo3d/GeoBBox.java   |   36 -
 .../org/apache/lucene/geo3d/GeoBBoxFactory.java |  111 --
 .../org/apache/lucene/geo3d/GeoBaseBBox.java    |   72 -
 .../org/apache/lucene/geo3d/GeoBaseCircle.java  |   34 -
 .../lucene/geo3d/GeoBaseDistanceShape.java      |   56 -
 .../lucene/geo3d/GeoBaseMembershipShape.java    |   56 -
 .../org/apache/lucene/geo3d/GeoBasePolygon.java |   34 -
 .../org/apache/lucene/geo3d/GeoBaseShape.java   |   59 -
 .../java/org/apache/lucene/geo3d/GeoCircle.java |   25 -
 .../apache/lucene/geo3d/GeoCircleFactory.java   |   43 -
 .../geo3d/GeoCompositeMembershipShape.java      |  117 --
 .../lucene/geo3d/GeoCompositePolygon.java       |   31 -
 .../apache/lucene/geo3d/GeoConvexPolygon.java   |  288 ---
 .../geo3d/GeoDegenerateHorizontalLine.java      |  215 ---
 .../lucene/geo3d/GeoDegenerateLatitudeZone.java |  138 --
 .../geo3d/GeoDegenerateLongitudeSlice.java      |  153 --
 .../apache/lucene/geo3d/GeoDegeneratePoint.java |  135 --
 .../lucene/geo3d/GeoDegenerateVerticalLine.java |  205 ---
 .../org/apache/lucene/geo3d/GeoDistance.java    |   59 -
 .../apache/lucene/geo3d/GeoDistanceShape.java   |   27 -
 .../apache/lucene/geo3d/GeoLatitudeZone.java    |  198 ---
 .../apache/lucene/geo3d/GeoLongitudeSlice.java  |  204 ---
 .../apache/lucene/geo3d/GeoMembershipShape.java |   27 -
 .../lucene/geo3d/GeoNorthLatitudeZone.java      |  165 --
 .../apache/lucene/geo3d/GeoNorthRectangle.java  |  263 ---
 .../apache/lucene/geo3d/GeoOutsideDistance.java |   55 -
 .../java/org/apache/lucene/geo3d/GeoPath.java   |  797 ---------
 .../java/org/apache/lucene/geo3d/GeoPoint.java  |  193 --
 .../org/apache/lucene/geo3d/GeoPolygon.java     |   26 -
 .../apache/lucene/geo3d/GeoPolygonFactory.java  |  187 --
 .../org/apache/lucene/geo3d/GeoRectangle.java   |  288 ---
 .../java/org/apache/lucene/geo3d/GeoShape.java  |   63 -
 .../org/apache/lucene/geo3d/GeoSizeable.java    |   40 -
 .../lucene/geo3d/GeoSouthLatitudeZone.java      |  168 --
 .../apache/lucene/geo3d/GeoSouthRectangle.java  |  259 ---
 .../apache/lucene/geo3d/GeoStandardCircle.java  |  168 --
 .../geo3d/GeoWideDegenerateHorizontalLine.java  |  238 ---
 .../lucene/geo3d/GeoWideLongitudeSlice.java     |  208 ---
 .../lucene/geo3d/GeoWideNorthRectangle.java     |  286 ---
 .../apache/lucene/geo3d/GeoWideRectangle.java   |  319 ----
 .../lucene/geo3d/GeoWideSouthRectangle.java     |  284 ---
 .../java/org/apache/lucene/geo3d/GeoWorld.java  |  106 --
 .../org/apache/lucene/geo3d/LatLonBounds.java   |  322 ----
 .../org/apache/lucene/geo3d/LinearDistance.java |   56 -
 .../lucene/geo3d/LinearSquaredDistance.java     |   56 -
 .../org/apache/lucene/geo3d/Membership.java     |   46 -
 .../org/apache/lucene/geo3d/NormalDistance.java |   56 -
 .../lucene/geo3d/NormalSquaredDistance.java     |   56 -
 .../src/java/org/apache/lucene/geo3d/Plane.java | 1657 ------------------
 .../org/apache/lucene/geo3d/PlanetModel.java    |  277 ---
 .../lucene/geo3d/PointInGeo3DShapeQuery.java    |  210 ---
 .../org/apache/lucene/geo3d/SidedPlane.java     |  175 --
 .../apache/lucene/geo3d/StandardXYZSolid.java   |  417 -----
 .../src/java/org/apache/lucene/geo3d/Tools.java |   41 -
 .../java/org/apache/lucene/geo3d/Vector.java    |  378 ----
 .../java/org/apache/lucene/geo3d/XYZBounds.java |  267 ---
 .../java/org/apache/lucene/geo3d/XYZSolid.java  |   26 -
 .../apache/lucene/geo3d/XYZSolidFactory.java    |   67 -
 .../java/org/apache/lucene/geo3d/XYdZSolid.java |  213 ---
 .../java/org/apache/lucene/geo3d/XdYZSolid.java |  212 ---
 .../org/apache/lucene/geo3d/XdYdZSolid.java     |  138 --
 .../java/org/apache/lucene/geo3d/dXYZSolid.java |  216 ---
 .../org/apache/lucene/geo3d/dXYdZSolid.java     |  138 --
 .../org/apache/lucene/geo3d/dXdYZSolid.java     |  138 --
 .../org/apache/lucene/geo3d/dXdYdZSolid.java    |  146 --
 .../org/apache/lucene/geo3d/package-info.java   |   21 -
 .../org/apache/lucene/spatial3d/Geo3DPoint.java |  114 ++
 .../org/apache/lucene/spatial3d/Geo3DUtil.java  |   59 +
 .../spatial3d/PointInGeo3DShapeQuery.java       |  215 +++
 .../lucene/spatial3d/geom/ArcDistance.java      |   56 +
 .../lucene/spatial3d/geom/BasePlanetObject.java |   57 +
 .../lucene/spatial3d/geom/BaseXYZSolid.java     |  167 ++
 .../apache/lucene/spatial3d/geom/Bounds.java    |  113 ++
 .../lucene/spatial3d/geom/DistanceStyle.java    |   83 +
 .../apache/lucene/spatial3d/geom/GeoArea.java   |   67 +
 .../lucene/spatial3d/geom/GeoAreaFactory.java   |   55 +
 .../apache/lucene/spatial3d/geom/GeoBBox.java   |   36 +
 .../lucene/spatial3d/geom/GeoBBoxFactory.java   |  111 ++
 .../lucene/spatial3d/geom/GeoBaseBBox.java      |   72 +
 .../lucene/spatial3d/geom/GeoBaseCircle.java    |   34 +
 .../spatial3d/geom/GeoBaseDistanceShape.java    |   56 +
 .../spatial3d/geom/GeoBaseMembershipShape.java  |   56 +
 .../lucene/spatial3d/geom/GeoBasePolygon.java   |   34 +
 .../lucene/spatial3d/geom/GeoBaseShape.java     |   59 +
 .../apache/lucene/spatial3d/geom/GeoCircle.java |   25 +
 .../lucene/spatial3d/geom/GeoCircleFactory.java |   43 +
 .../geom/GeoCompositeMembershipShape.java       |  117 ++
 .../spatial3d/geom/GeoCompositePolygon.java     |   31 +
 .../lucene/spatial3d/geom/GeoConvexPolygon.java |  288 +++
 .../geom/GeoDegenerateHorizontalLine.java       |  215 +++
 .../geom/GeoDegenerateLatitudeZone.java         |  138 ++
 .../geom/GeoDegenerateLongitudeSlice.java       |  153 ++
 .../spatial3d/geom/GeoDegeneratePoint.java      |  135 ++
 .../geom/GeoDegenerateVerticalLine.java         |  205 +++
 .../lucene/spatial3d/geom/GeoDistance.java      |   59 +
 .../lucene/spatial3d/geom/GeoDistanceShape.java |   27 +
 .../lucene/spatial3d/geom/GeoLatitudeZone.java  |  198 +++
 .../spatial3d/geom/GeoLongitudeSlice.java       |  204 +++
 .../spatial3d/geom/GeoMembershipShape.java      |   27 +
 .../spatial3d/geom/GeoNorthLatitudeZone.java    |  165 ++
 .../spatial3d/geom/GeoNorthRectangle.java       |  263 +++
 .../spatial3d/geom/GeoOutsideDistance.java      |   55 +
 .../apache/lucene/spatial3d/geom/GeoPath.java   |  797 +++++++++
 .../apache/lucene/spatial3d/geom/GeoPoint.java  |  193 ++
 .../lucene/spatial3d/geom/GeoPolygon.java       |   26 +
 .../spatial3d/geom/GeoPolygonFactory.java       |  187 ++
 .../lucene/spatial3d/geom/GeoRectangle.java     |  288 +++
 .../apache/lucene/spatial3d/geom/GeoShape.java  |   63 +
 .../lucene/spatial3d/geom/GeoSizeable.java      |   40 +
 .../spatial3d/geom/GeoSouthLatitudeZone.java    |  168 ++
 .../spatial3d/geom/GeoSouthRectangle.java       |  259 +++
 .../spatial3d/geom/GeoStandardCircle.java       |  168 ++
 .../geom/GeoWideDegenerateHorizontalLine.java   |  238 +++
 .../spatial3d/geom/GeoWideLongitudeSlice.java   |  208 +++
 .../spatial3d/geom/GeoWideNorthRectangle.java   |  286 +++
 .../lucene/spatial3d/geom/GeoWideRectangle.java |  319 ++++
 .../spatial3d/geom/GeoWideSouthRectangle.java   |  284 +++
 .../apache/lucene/spatial3d/geom/GeoWorld.java  |  106 ++
 .../lucene/spatial3d/geom/LatLonBounds.java     |  322 ++++
 .../lucene/spatial3d/geom/LinearDistance.java   |   56 +
 .../spatial3d/geom/LinearSquaredDistance.java   |   56 +
 .../lucene/spatial3d/geom/Membership.java       |   46 +
 .../lucene/spatial3d/geom/NormalDistance.java   |   56 +
 .../spatial3d/geom/NormalSquaredDistance.java   |   56 +
 .../org/apache/lucene/spatial3d/geom/Plane.java | 1657 ++++++++++++++++++
 .../lucene/spatial3d/geom/PlanetModel.java      |  277 +++
 .../lucene/spatial3d/geom/SidedPlane.java       |  175 ++
 .../lucene/spatial3d/geom/StandardXYZSolid.java |  417 +++++
 .../org/apache/lucene/spatial3d/geom/Tools.java |   41 +
 .../apache/lucene/spatial3d/geom/Vector.java    |  378 ++++
 .../apache/lucene/spatial3d/geom/XYZBounds.java |  267 +++
 .../apache/lucene/spatial3d/geom/XYZSolid.java  |   26 +
 .../lucene/spatial3d/geom/XYZSolidFactory.java  |   67 +
 .../apache/lucene/spatial3d/geom/XYdZSolid.java |  213 +++
 .../apache/lucene/spatial3d/geom/XdYZSolid.java |  212 +++
 .../lucene/spatial3d/geom/XdYdZSolid.java       |  138 ++
 .../apache/lucene/spatial3d/geom/dXYZSolid.java |  216 +++
 .../lucene/spatial3d/geom/dXYdZSolid.java       |  138 ++
 .../lucene/spatial3d/geom/dXdYZSolid.java       |  138 ++
 .../lucene/spatial3d/geom/dXdYdZSolid.java      |  146 ++
 .../lucene/spatial3d/geom/package-info.java     |   22 +
 .../apache/lucene/spatial3d/package-info.java   |   21 +
 lucene/spatial3d/src/java/overview.html         |    3 +-
 .../org/apache/lucene/geo3d/GeoBBoxTest.java    |  364 ----
 .../org/apache/lucene/geo3d/GeoCircleTest.java  |  415 -----
 .../lucene/geo3d/GeoConvexPolygonTest.java      |   91 -
 .../org/apache/lucene/geo3d/GeoModelTest.java   |  110 --
 .../org/apache/lucene/geo3d/GeoPathTest.java    |  270 ---
 .../org/apache/lucene/geo3d/GeoPolygonTest.java |  165 --
 .../test/org/apache/lucene/geo3d/PlaneTest.java |   64 -
 .../org/apache/lucene/geo3d/TestGeo3DPoint.java |  801 ---------
 .../org/apache/lucene/geo3d/XYZSolidTest.java   |  220 ---
 .../apache/lucene/spatial3d/TestGeo3DPoint.java |  810 +++++++++
 .../lucene/spatial3d/geom/GeoBBoxTest.java      |  364 ++++
 .../lucene/spatial3d/geom/GeoCircleTest.java    |  410 +++++
 .../spatial3d/geom/GeoConvexPolygonTest.java    |   91 +
 .../lucene/spatial3d/geom/GeoModelTest.java     |  110 ++
 .../lucene/spatial3d/geom/GeoPathTest.java      |  270 +++
 .../lucene/spatial3d/geom/GeoPointTest.java     |   77 +
 .../lucene/spatial3d/geom/GeoPolygonTest.java   |  165 ++
 .../apache/lucene/spatial3d/geom/PlaneTest.java |   64 +
 .../lucene/spatial3d/geom/XYZSolidTest.java     |  220 +++
 178 files changed, 15186 insertions(+), 15153 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/CHANGES.txt
----------------------------------------------------------------------
diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index 290421a..ca59e6b 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -126,6 +126,8 @@ API Changes
 * LUCENE-7072: Geo3DPoint always uses WGS84 planet model.
   (Robert Muir, Mike McCandless)
 
+* LUCENE-7056: Geo3D classes are in different packages now. (David Smiley)
+
 Optimizations
 
 * LUCENE-6891: Use prefix coding when writing points in 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dShape.java b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dShape.java
index 518fb32..9fa6d8e 100644
--- a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dShape.java
+++ b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dShape.java
@@ -23,12 +23,12 @@ import org.locationtech.spatial4j.shape.Rectangle;
 import org.locationtech.spatial4j.shape.Shape;
 import org.locationtech.spatial4j.shape.SpatialRelation;
 import org.locationtech.spatial4j.shape.impl.RectangleImpl;
-import org.apache.lucene.geo3d.LatLonBounds;
-import org.apache.lucene.geo3d.GeoArea;
-import org.apache.lucene.geo3d.GeoAreaFactory;
-import org.apache.lucene.geo3d.GeoPoint;
-import org.apache.lucene.geo3d.GeoShape;
-import org.apache.lucene.geo3d.PlanetModel;
+import org.apache.lucene.spatial3d.geom.LatLonBounds;
+import org.apache.lucene.spatial3d.geom.GeoArea;
+import org.apache.lucene.spatial3d.geom.GeoAreaFactory;
+import org.apache.lucene.spatial3d.geom.GeoPoint;
+import org.apache.lucene.spatial3d.geom.GeoShape;
+import org.apache.lucene.spatial3d.geom.PlanetModel;
 
 /**
  * A Spatial4j Shape wrapping a {@link GeoShape} ("Geo3D") -- a 3D planar geometry based Spatial4j Shape implementation.

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/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
index d26bb29..e62b857 100644
--- 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
@@ -32,13 +32,13 @@ 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.apache.lucene.spatial3d.geom.GeoBBoxFactory;
+import org.apache.lucene.spatial3d.geom.GeoStandardCircle;
+import org.apache.lucene.spatial3d.geom.GeoPath;
+import org.apache.lucene.spatial3d.geom.GeoPoint;
+import org.apache.lucene.spatial3d.geom.GeoPolygonFactory;
+import org.apache.lucene.spatial3d.geom.GeoShape;
+import org.apache.lucene.spatial3d.geom.PlanetModel;
 import org.junit.Test;
 
 import static org.locationtech.spatial4j.distance.DistanceUtils.DEGREES_TO_RADIANS;

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/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
index 134b8c7..d58985f 100644
--- 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
@@ -25,15 +25,15 @@ import org.locationtech.spatial4j.distance.DistanceUtils;
 import org.locationtech.spatial4j.shape.Circle;
 import org.locationtech.spatial4j.shape.Point;
 import org.locationtech.spatial4j.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.apache.lucene.spatial3d.geom.LatLonBounds;
+import org.apache.lucene.spatial3d.geom.GeoBBox;
+import org.apache.lucene.spatial3d.geom.GeoBBoxFactory;
+import org.apache.lucene.spatial3d.geom.GeoStandardCircle;
+import org.apache.lucene.spatial3d.geom.GeoPath;
+import org.apache.lucene.spatial3d.geom.GeoPoint;
+import org.apache.lucene.spatial3d.geom.GeoPolygonFactory;
+import org.apache.lucene.spatial3d.geom.GeoShape;
+import org.apache.lucene.spatial3d.geom.PlanetModel;
 import org.junit.Rule;
 import org.junit.Test;
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/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
index 2d95823..3bce480 100644
--- 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
@@ -20,14 +20,14 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.locationtech.spatial4j.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.apache.lucene.spatial3d.geom.GeoArea;
+import org.apache.lucene.spatial3d.geom.GeoBBox;
+import org.apache.lucene.spatial3d.geom.GeoBBoxFactory;
+import org.apache.lucene.spatial3d.geom.GeoStandardCircle;
+import org.apache.lucene.spatial3d.geom.GeoPoint;
+import org.apache.lucene.spatial3d.geom.GeoPolygonFactory;
+import org.apache.lucene.spatial3d.geom.GeoShape;
+import org.apache.lucene.spatial3d.geom.PlanetModel;
 import org.junit.Test;
 
 public class Geo3dShapeSphereModelRectRelationTest extends Geo3dShapeRectRelationTestCase {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/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
index 3b026c3..b59d7df 100644
--- 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
@@ -16,14 +16,14 @@
  */
 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.apache.lucene.spatial3d.geom.GeoArea;
+import org.apache.lucene.spatial3d.geom.GeoBBox;
+import org.apache.lucene.spatial3d.geom.GeoBBoxFactory;
+import org.apache.lucene.spatial3d.geom.GeoCircle;
+import org.apache.lucene.spatial3d.geom.GeoStandardCircle;
+import org.apache.lucene.spatial3d.geom.GeoPath;
+import org.apache.lucene.spatial3d.geom.GeoPoint;
+import org.apache.lucene.spatial3d.geom.PlanetModel;
 import org.junit.Test;
 
 public class Geo3dShapeWGS84ModelRectRelationTest extends Geo3dShapeRectRelationTestCase {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/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
deleted file mode 100644
index 4446474..0000000
--- a/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/geo3d/GeoPointTest.java
+++ /dev/null
@@ -1,80 +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.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 org.locationtech.spatial4j.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/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/ArcDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/ArcDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/ArcDistance.java
deleted file mode 100644
index c49fd1f..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/ArcDistance.java
+++ /dev/null
@@ -1,56 +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.geo3d;
-
-/**
- * Arc distance computation style.
- *
- * @lucene.experimental
- */
-public class ArcDistance implements DistanceStyle {
-  
-  /** An instance of the ArcDistance DistanceStyle. */
-  public final static ArcDistance INSTANCE = new ArcDistance();
-  
-  /** Constructor.
-   */
-  public ArcDistance() {
-  }
-  
-  @Override
-  public double computeDistance(final GeoPoint point1, final GeoPoint point2) {
-    return point1.arcDistance(point2);
-  }
-  
-  @Override
-  public double computeDistance(final GeoPoint point1, final double x2, final double y2, final double z2) {
-    return point1.arcDistance(x2,y2,z2);
-  }
-
-  @Override
-  public double computeDistance(final PlanetModel planetModel, final Plane plane, final GeoPoint point, final Membership... bounds) {
-    return plane.arcDistance(planetModel, point, bounds);
-  }
-  
-  @Override
-  public double computeDistance(final PlanetModel planetModel, final Plane plane, final double x, final double y, final double z, final Membership... bounds) {
-    return plane.arcDistance(planetModel, x,y,z, bounds);
-  }
-
-}
-
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/BasePlanetObject.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/BasePlanetObject.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/BasePlanetObject.java
deleted file mode 100644
index c64b974..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/BasePlanetObject.java
+++ /dev/null
@@ -1,57 +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.geo3d;
-
-/**
- * All Geo3D shapes can derive from this base class, which furnishes
- * some common code
- *
- * @lucene.internal
- */
-public abstract class BasePlanetObject {
-
-  /** This is the planet model embedded in all objects derived from this
-   * class. */
-  protected final PlanetModel planetModel;
-  
-  /** Constructor creating class instance given a planet model.
-   * @param planetModel is the planet model.
-   */
-  public BasePlanetObject(final PlanetModel planetModel) {
-    this.planetModel = planetModel;
-  }
-
-  /** Returns the {@link PlanetModel} provided when this shape was created. */
-  public PlanetModel getPlanetModel() {
-    return planetModel;
-  }
-  
-  @Override
-  public int hashCode() {
-    return planetModel.hashCode();
-  }
-  
-  @Override
-  public boolean equals(final Object o) {
-    if (!(o instanceof BasePlanetObject))
-      return false;
-    return planetModel.equals(((BasePlanetObject)o).planetModel);
-  }
-}
-
-
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/BaseXYZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/BaseXYZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/BaseXYZSolid.java
deleted file mode 100644
index 52bd5da..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/BaseXYZSolid.java
+++ /dev/null
@@ -1,167 +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.geo3d;
-
-/**
- * Base class of a family of 3D rectangles, bounded on six sides by X,Y,Z limits
- *
- * @lucene.internal
- */
-public abstract class BaseXYZSolid extends BasePlanetObject implements XYZSolid {
-
-  /** Unit vector in x */
-  protected static final Vector xUnitVector = new Vector(1.0, 0.0, 0.0);
-  /** Unit vector in y */
-  protected static final Vector yUnitVector = new Vector(0.0, 1.0, 0.0);
-  /** Unit vector in z */
-  protected static final Vector zUnitVector = new Vector(0.0, 0.0, 1.0);
-  
-  /** Vertical plane normal to x unit vector passing through origin */
-  protected static final Plane xVerticalPlane = new Plane(0.0, 1.0, 0.0, 0.0);
-  /** Vertical plane normal to y unit vector passing through origin */
-  protected static final Plane yVerticalPlane = new Plane(1.0, 0.0, 0.0, 0.0);
-
-  /** Empty point vector */
-  protected static final GeoPoint[] EMPTY_POINTS = new GeoPoint[0];
-  
-  /**
-   * Base solid constructor.
-   *@param planetModel is the planet model.
-   */
-  public BaseXYZSolid(final PlanetModel planetModel) {
-    super(planetModel);
-  }
-  
-  /** Construct a single array from a number of individual arrays.
-   * @param pointArrays is the array of point arrays.
-   * @return the single unified array.
-   */
-  protected static GeoPoint[] glueTogether(final GeoPoint[]... pointArrays) {
-    int count = 0;
-    for (final GeoPoint[] pointArray : pointArrays) {
-      count += pointArray.length;
-    }
-    final GeoPoint[] rval = new GeoPoint[count];
-    count = 0;
-    for (final GeoPoint[] pointArray : pointArrays) {
-      for (final GeoPoint point : pointArray) {
-        rval[count++] = point;
-      }
-    }
-    return rval;
-  }
-  
-  @Override
-  public boolean isWithin(final Vector point) {
-    return isWithin(point.x, point.y, point.z);
-  }
-  
-  @Override
-  public abstract boolean isWithin(final double x, final double y, final double z);
-  
-  // Signals for relationship of edge points to shape
-  
-  /** All edgepoints inside shape */
-  protected final static int ALL_INSIDE = 0;
-  /** Some edgepoints inside shape */
-  protected final static int SOME_INSIDE = 1;
-  /** No edgepoints inside shape */
-  protected final static int NONE_INSIDE = 2;
-  /** No edgepoints at all (means a shape that is the whole world) */
-  protected final static int NO_EDGEPOINTS = 3;
-
-  /** Determine the relationship between this area and the provided
-   * shape's edgepoints.
-   *@param path is the shape.
-   *@return the relationship.
-   */
-  protected int isShapeInsideArea(final GeoShape path) {
-    final GeoPoint[] pathPoints = path.getEdgePoints();
-    if (pathPoints.length == 0)
-      return NO_EDGEPOINTS;
-    boolean foundOutside = false;
-    boolean foundInside = false;
-    for (final GeoPoint p : pathPoints) {
-      if (isWithin(p)) {
-        foundInside = true;
-      } else {
-        foundOutside = true;
-      }
-      if (foundInside && foundOutside) {
-        return SOME_INSIDE;
-      }
-    }
-    if (!foundInside && !foundOutside)
-      return NONE_INSIDE;
-    if (foundInside && !foundOutside)
-      return ALL_INSIDE;
-    if (foundOutside && !foundInside)
-      return NONE_INSIDE;
-    return SOME_INSIDE;
-  }
-
-  /** Determine the relationship between a shape and this area's
-   * edgepoints.
-   *@param path is the shape.
-   *@return the relationship.
-   */
-  protected int isAreaInsideShape(final GeoShape path) {
-    final GeoPoint[] edgePoints = getEdgePoints();
-    if (edgePoints.length == 0) {
-      return NO_EDGEPOINTS;
-    }
-    boolean foundOutside = false;
-    boolean foundInside = false;
-    for (final GeoPoint p : edgePoints) {
-      if (path.isWithin(p)) {
-        foundInside = true;
-      } else {
-        foundOutside = true;
-      }
-      if (foundInside && foundOutside) {
-        return SOME_INSIDE;
-      }
-    }
-    if (!foundInside && !foundOutside)
-      return NONE_INSIDE;
-    if (foundInside && !foundOutside)
-      return ALL_INSIDE;
-    if (foundOutside && !foundInside)
-      return NONE_INSIDE;
-    return SOME_INSIDE;
-  }
-
-  /** Get the edge points for this shape.
-   *@return the edge points.
-   */
-  protected abstract GeoPoint[] getEdgePoints();
-  
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof BaseXYZSolid))
-      return false;
-    BaseXYZSolid other = (BaseXYZSolid) o;
-    return super.equals(other);
-  }
-
-  @Override
-  public int hashCode() {
-    return super.hashCode();
-  }
-
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Bounds.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Bounds.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Bounds.java
deleted file mode 100755
index 6717220..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Bounds.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.geo3d;
-
-/**
- * An interface for accumulating bounds information.
- * The bounds object is initially empty.  Bounding points
- * are then applied by supplying (x,y,z) tuples.  It is also
- * possible to indicate the following edge cases:
- * (1) No longitude bound possible
- * (2) No upper latitude bound possible
- * (3) No lower latitude bound possible
- * When any of these have been applied, further application of
- * points cannot override that decision.
- *
- * @lucene.experimental
- */
-public interface Bounds {
-
-  /** Add a general plane to the bounds description.
-   *@param planetModel is the planet model.
-   *@param plane is the plane.
-   *@param bounds are the membership bounds for points along the arc.
-   */
-  public Bounds addPlane(final PlanetModel planetModel, final Plane plane, final Membership... bounds);
-  
-  /** Add a horizontal plane to the bounds description.
-   * This method should EITHER use the supplied latitude, OR use the supplied
-   * plane, depending on what is most efficient.
-   *@param planetModel is the planet model.
-   *@param latitude is the latitude.
-   *@param horizontalPlane is the plane.
-   *@param bounds are the constraints on the plane.
-   *@return updated Bounds object.
-   */
-  public Bounds addHorizontalPlane(final PlanetModel planetModel,
-    final double latitude,
-    final Plane horizontalPlane,
-    final Membership... bounds);
-    
-  /** Add a vertical plane to the bounds description.
-   * This method should EITHER use the supplied longitude, OR use the supplied
-   * plane, depending on what is most efficient.
-   *@param planetModel is the planet model.
-   *@param longitude is the longitude.
-   *@param verticalPlane is the plane.
-   *@param bounds are the constraints on the plane.
-   *@return updated Bounds object.
-   */
-  public Bounds addVerticalPlane(final PlanetModel planetModel,
-    final double longitude,
-    final Plane verticalPlane,
-    final Membership... bounds);
-
-  /** Add a single point.
-   *@param point is the point.
-   *@return the updated Bounds object.
-   */
-  public Bounds addPoint(final GeoPoint point);
-
-  /** Add an X value.
-   *@param point is the point to take the x value from.
-   *@return the updated object.
-   */
-  public Bounds addXValue(final GeoPoint point);
-
-  /** Add a Y value.
-   *@param point is the point to take the y value from.
-   *@return the updated object.
-   */
-  public Bounds addYValue(final GeoPoint point);
-
-  /** Add a Z value.
-   *@param point is the point to take the z value from.
-   *@return the updated object.
-   */
-  public Bounds addZValue(final GeoPoint point);
-  
-  /** Signal that the shape exceeds Math.PI in longitude.
-   *@return the updated Bounds object.
-   */
-  public Bounds isWide();
-  
-  /** Signal that there is no longitude bound.
-   *@return the updated Bounds object.
-   */
-  public Bounds noLongitudeBound();
-
-  /** Signal that there is no top latitude bound.
-   *@return the updated Bounds object.
-   */
-  public Bounds noTopLatitudeBound();
-
-  /** Signal that there is no bottom latitude bound.
-   *@return the updated Bounds object.
-   */
-  public Bounds noBottomLatitudeBound();
-  
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/DistanceStyle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/DistanceStyle.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/DistanceStyle.java
deleted file mode 100644
index 28056cb..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/DistanceStyle.java
+++ /dev/null
@@ -1,83 +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.geo3d;
-
-/**
- * Distance computation styles, supporting various ways of computing
- * distance to shapes.
- *
- * @lucene.experimental
- */
-public interface DistanceStyle {
-
-  // convenient access to built-in styles:
-
-  /** Arc distance calculator */
-  public static final ArcDistance ARC = ArcDistance.INSTANCE;
-  /** Linear distance calculator */
-  public static final LinearDistance LINEAR = LinearDistance.INSTANCE;
-  /** Linear distance squared calculator */
-  public static final LinearSquaredDistance LINEAR_SQUARED = LinearSquaredDistance.INSTANCE;
-  /** Normal distance calculator */
-  public static final NormalDistance NORMAL = NormalDistance.INSTANCE;
-  /** Normal distance squared calculator */
-  public static final NormalSquaredDistance NORMAL_SQUARED = NormalSquaredDistance.INSTANCE;
-
-  /** Compute the distance from a point to another point.
-   * @param point1 Starting point
-   * @param point2 Final point
-   * @return the distance
-   */
-  public default double computeDistance(final GeoPoint point1, final GeoPoint point2) {
-    return computeDistance(point1, point2.x, point2.y, point2.z);
-  }
-  
-  /** Compute the distance from a point to another point.
-   * @param point1 Starting point
-   * @param x2 Final point x
-   * @param y2 Final point y
-   * @param z2 Final point z
-   * @return the distance
-   */
-  public double computeDistance(final GeoPoint point1, final double x2, final double y2, final double z2);
-
-  /** Compute the distance from a plane to a point.
-   * @param planetModel The planet model
-   * @param plane The plane
-   * @param point The point
-   * @param bounds are the plane bounds
-   * @return the distance
-   */
-  public default double computeDistance(final PlanetModel planetModel, final Plane plane, final GeoPoint point,
-                                        final Membership... bounds) {
-    return computeDistance(planetModel, plane, point.x, point.y, point.z, bounds);
-  }
-  
-  /** Compute the distance from a plane to a point.
-   * @param planetModel The planet model
-   * @param plane The plane
-   * @param x The point x
-   * @param y The point y
-   * @param z The point z
-   * @param bounds are the plane bounds
-   * @return the distance
-   */
-  public double computeDistance(final PlanetModel planetModel, final Plane plane, final double x, final double y, final double z, final Membership... bounds);
-
-}
-
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Geo3DPoint.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Geo3DPoint.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Geo3DPoint.java
deleted file mode 100644
index cde87f3..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Geo3DPoint.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.geo3d;
-
-import org.apache.lucene.document.Field;
-import org.apache.lucene.document.FieldType;
-import org.apache.lucene.search.Query;
-import org.apache.lucene.util.BytesRef;
-import org.apache.lucene.util.NumericUtils;
-import org.apache.lucene.util.RamUsageEstimator;
-
-/**
- * Add this to a document to index lat/lon or x/y/z point, indexed as a 3D point.
- * Multiple values are allowed: just add multiple Geo3DPoint to the document with the
- * same field name.
- * <p>
- * This field defines static factory methods for creating a shape query:
- * <ul>
- *   <li>{@link #newShapeQuery newShapeQuery()} for matching all points inside a specified shape
- * </ul>
- *
- *  @lucene.experimental */
-public final class Geo3DPoint extends Field {
-
-  /** Indexing {@link FieldType}. */
-  public static final FieldType TYPE = new FieldType();
-  static {
-    TYPE.setDimensions(3, Integer.BYTES);
-    TYPE.freeze();
-  }
-
-  /** 
-   * Creates a new Geo3DPoint field with the specified lat, lon (in radians).
-   *
-   * @throws IllegalArgumentException if the field name is null or lat or lon are out of bounds
-   */
-  public Geo3DPoint(String name, double lat, double lon) {
-    super(name, TYPE);
-    // Translate lat/lon to x,y,z:
-    final GeoPoint point = new GeoPoint(PlanetModel.WGS84, lat, lon);
-    fillFieldsData(point.x, point.y, point.z);
-  }
-
-  /** 
-   * Creates a new Geo3DPoint field with the specified x,y,z.
-   *
-   * @throws IllegalArgumentException if the field name is null or lat or lon are out of bounds
-   */
-  public Geo3DPoint(String name, double x, double y, double z) {
-    super(name, TYPE);
-    fillFieldsData(x, y, z);
-  }
-
-  private void fillFieldsData(double x, double y, double z) {
-    byte[] bytes = new byte[12];
-    encodeDimension(x, bytes, 0);
-    encodeDimension(y, bytes, Integer.BYTES);
-    encodeDimension(z, bytes, 2*Integer.BYTES);
-    fieldsData = new BytesRef(bytes);
-  }
-
-  // public helper methods (e.g. for queries)
-  
-  /** Encode single dimension */
-  public static void encodeDimension(double value, byte bytes[], int offset) {
-    NumericUtils.intToSortableBytes(Geo3DUtil.encodeValue(PlanetModel.WGS84.getMaximumMagnitude(), value), bytes, offset);
-  }
-  
-  /** Decode single dimension */
-  public static double decodeDimension(byte value[], int offset) {
-    return Geo3DUtil.decodeValueCenter(PlanetModel.WGS84.getMaximumMagnitude(), NumericUtils.sortableBytesToInt(value, offset));
-  }
-
-  /** Returns a query matching all points inside the provided shape.
-   * 
-   * @param field field name. must not be {@code null}.
-   * @param shape Which {@link GeoShape} to match
-   */
-  public static Query newShapeQuery(String field, GeoShape shape) {
-    return new PointInGeo3DShapeQuery(field, shape);
-  }
-
-  @Override
-  public String toString() {
-    StringBuilder result = new StringBuilder();
-    result.append(getClass().getSimpleName());
-    result.append(" <");
-    result.append(name);
-    result.append(':');
-
-    BytesRef bytes = (BytesRef) fieldsData;
-    result.append(" x=" + decodeDimension(bytes.bytes, bytes.offset));
-    result.append(" y=" + decodeDimension(bytes.bytes, bytes.offset + Integer.BYTES));
-    result.append(" z=" + decodeDimension(bytes.bytes, bytes.offset + 2*Integer.BYTES));
-    result.append('>');
-    return result.toString();
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Geo3DUtil.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Geo3DUtil.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Geo3DUtil.java
deleted file mode 100644
index 34880a1..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Geo3DUtil.java
+++ /dev/null
@@ -1,59 +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.geo3d;
-
-class Geo3DUtil {
-
-  /** Clips the incoming value to the allowed min/max range before encoding, instead of throwing an exception. */
-  public static int encodeValueLenient(double planetMax, double x) {
-    if (x > planetMax) {
-      x = planetMax;
-    } else if (x < -planetMax) {
-      x = -planetMax;
-    }
-    return encodeValue(planetMax, x);
-  }
-
-  public static int encodeValue(double planetMax, double x) {
-    if (x > planetMax) {
-      throw new IllegalArgumentException("value=" + x + " is out-of-bounds (greater than planetMax=" + planetMax + ")");
-    }
-    if (x < -planetMax) {
-      throw new IllegalArgumentException("value=" + x + " is out-of-bounds (less than than -planetMax=" + -planetMax + ")");
-    }
-    long y = Math.round (x * (Integer.MAX_VALUE / planetMax));
-    assert y >= Integer.MIN_VALUE;
-    assert y <= Integer.MAX_VALUE;
-
-    return (int) y;
-  }
-
-  /** Center decode */
-  public static double decodeValueCenter(double planetMax, int x) {
-    return x * (planetMax / Integer.MAX_VALUE);
-  }
-
-  /** More negative decode, at bottom of cell */
-  public static double decodeValueMin(double planetMax, int x) {
-    return (((double)x) - 0.5) * (planetMax / Integer.MAX_VALUE);
-  }
-  
-  /** More positive decode, at top of cell  */
-  public static double decodeValueMax(double planetMax, int x) {
-    return (((double)x) + 0.5) * (planetMax / Integer.MAX_VALUE);
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoArea.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoArea.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoArea.java
deleted file mode 100755
index 424e494..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoArea.java
+++ /dev/null
@@ -1,67 +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.geo3d;
-
-/**
- * A GeoArea represents a standard 2-D breakdown of a part of sphere.  It can
- * be bounded in latitude, or bounded in both latitude and longitude, or not
- * bounded at all.  The purpose of the interface is to describe bounding shapes used for
- * computation of geo hashes.
- *
- * @lucene.experimental
- */
-public interface GeoArea extends Membership {
-  // Since we don't know what each GeoArea's constraints are,
-  // we put the onus on the GeoArea implementation to do the right thing.
-  // This will, of course, rely heavily on methods provided by
-  // the underlying GeoShape class.
-
-  // Relationship values for "getRelationship()"
-  
-  /** The referenced shape CONTAINS this area */
-  public static final int CONTAINS = 0;
-  /** The referenced shape IS WITHIN this area */
-  public static final int WITHIN = 1;
-  /** The referenced shape OVERLAPS this area */
-  public static final int OVERLAPS = 2;
-  /** The referenced shape has no relation to this area */
-  public static final int DISJOINT = 3;
-
-  /**
-   * Find the spatial relationship between a shape and the current geo area.
-   * Note: return value is how the GeoShape relates to the GeoArea, not the
-   * other way around. For example, if this GeoArea is entirely within the
-   * shape, then CONTAINS should be returned.  If the shape is entirely enclosed
-   * by this GeoArea, then WITHIN should be returned.
-   *
-   * It is permissible to return OVERLAPS instead of WITHIN if the shape
-   * intersects with the area at even a single point.  So, a circle inscribed in
-   * a rectangle could return either OVERLAPS or WITHIN, depending on
-   * implementation.  It is not permissible to return CONTAINS or DISJOINT
-   * in this circumstance, however.
-   *
-   * Similarly, it is permissible to return OVERLAPS instead of CONTAINS
-   * under conditions where the shape consists of multiple independent overlapping
-   * subshapes, and the area overlaps one of the subshapes.  It is not permissible
-   * to return WITHIN or DISJOINT in this circumstance, however.
-   *
-   * @param shape is the shape to consider.
-   * @return the relationship, from the perspective of the shape.
-   */
-  public int getRelationship(GeoShape shape);
-}
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoAreaFactory.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoAreaFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoAreaFactory.java
deleted file mode 100755
index 24dd211..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoAreaFactory.java
+++ /dev/null
@@ -1,55 +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.geo3d;
-
-/**
- * Factory for {@link org.apache.lucene.geo3d.GeoArea}.
- *
- * @lucene.experimental
- */
-public class GeoAreaFactory {
-  private GeoAreaFactory() {
-  }
-
-  /**
-   * Create a GeoArea of the right kind given the specified bounds.
-   * @param planetModel is the planet model
-   * @param topLat    is the top latitude
-   * @param bottomLat is the bottom latitude
-   * @param leftLon   is the left longitude
-   * @param rightLon  is the right longitude
-   * @return a GeoArea corresponding to what was specified.
-   */
-  public static GeoArea makeGeoArea(final PlanetModel planetModel, final double topLat, final double bottomLat, final double leftLon, final double rightLon) {
-    return GeoBBoxFactory.makeGeoBBox(planetModel, topLat, bottomLat, leftLon, rightLon);
-  }
-
-  /**
-   * Create a GeoArea of the right kind given (x,y,z) bounds.
-   * @param planetModel is the planet model
-   * @param minX is the min X boundary
-   * @param maxX is the max X boundary
-   * @param minY is the min Y boundary
-   * @param maxY is the max Y boundary
-   * @param minZ is the min Z boundary
-   * @param maxZ is the max Z boundary
-   */
-  public static GeoArea makeGeoArea(final PlanetModel planetModel, final double minX, final double maxX, final double minY, final double maxY, final double minZ, final double maxZ) {
-    return XYZSolidFactory.makeXYZSolid(planetModel, minX, maxX, minY, maxY, minZ, maxZ);
-  }
-  
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBBox.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBBox.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBBox.java
deleted file mode 100755
index 10a2388..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBBox.java
+++ /dev/null
@@ -1,36 +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.geo3d;
-
-/**
- * All bounding box shapes have this interface in common.
- * This describes methods that bounding boxes have above and beyond
- * GeoMembershipShape's.
- *
- * @lucene.experimental
- */
-public interface GeoBBox extends GeoMembershipShape, GeoSizeable, GeoArea {
-
-  /**
-   * Expand box by specified angle.
-   *
-   * @param angle is the angle amount to expand the GeoBBox by.
-   * @return a new GeoBBox.
-   */
-  public GeoBBox expand(double angle);
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBBoxFactory.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBBoxFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBBoxFactory.java
deleted file mode 100755
index 9a02ab9..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBBoxFactory.java
+++ /dev/null
@@ -1,111 +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.geo3d;
-
-/**
- * Factory for {@link org.apache.lucene.geo3d.GeoBBox}.
- *
- * @lucene.experimental
- */
-public class GeoBBoxFactory {
-  private GeoBBoxFactory() {
-  }
-
-  /**
-   * Create a geobbox of the right kind given the specified bounds.
-   *
-   * @param planetModel is the planet model
-   * @param topLat    is the top latitude
-   * @param bottomLat is the bottom latitude
-   * @param leftLon   is the left longitude
-   * @param rightLon  is the right longitude
-   * @return a GeoBBox corresponding to what was specified.
-   */
-  public static GeoBBox makeGeoBBox(final PlanetModel planetModel, double topLat, double bottomLat, double leftLon, double rightLon) {
-    //System.err.println("Making rectangle for topLat="+topLat*180.0/Math.PI+", bottomLat="+bottomLat*180.0/Math.PI+", leftLon="+leftLon*180.0/Math.PI+", rightlon="+rightLon*180.0/Math.PI);
-    if (topLat > Math.PI * 0.5)
-      topLat = Math.PI * 0.5;
-    if (bottomLat < -Math.PI * 0.5)
-      bottomLat = -Math.PI * 0.5;
-    if (leftLon < -Math.PI)
-      leftLon = -Math.PI;
-    if (rightLon > Math.PI)
-      rightLon = Math.PI;
-    if (Math.abs(leftLon + Math.PI) < Vector.MINIMUM_RESOLUTION && Math.abs(rightLon - Math.PI) < Vector.MINIMUM_RESOLUTION) {
-      if (Math.abs(topLat - Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION && Math.abs(bottomLat + Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION)
-        return new GeoWorld(planetModel);
-      if (Math.abs(topLat - bottomLat) < Vector.MINIMUM_RESOLUTION) {
-        if (Math.abs(topLat - Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION || Math.abs(topLat + Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION)
-          return new GeoDegeneratePoint(planetModel, topLat, 0.0);
-        return new GeoDegenerateLatitudeZone(planetModel, topLat);
-      }
-      if (Math.abs(topLat - Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION)
-        return new GeoNorthLatitudeZone(planetModel, bottomLat);
-      else if (Math.abs(bottomLat + Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION)
-        return new GeoSouthLatitudeZone(planetModel, topLat);
-      return new GeoLatitudeZone(planetModel, topLat, bottomLat);
-    }
-    //System.err.println(" not latitude zone");
-    double extent = rightLon - leftLon;
-    if (extent < 0.0)
-      extent += Math.PI * 2.0;
-    if (topLat == Math.PI * 0.5 && bottomLat == -Math.PI * 0.5) {
-      if (Math.abs(leftLon - rightLon) < Vector.MINIMUM_RESOLUTION)
-        return new GeoDegenerateLongitudeSlice(planetModel, leftLon);
-
-      if (extent >= Math.PI)
-        return new GeoWideLongitudeSlice(planetModel, leftLon, rightLon);
-
-      return new GeoLongitudeSlice(planetModel, leftLon, rightLon);
-    }
-    //System.err.println(" not longitude slice");
-    if (Math.abs(leftLon - rightLon) < Vector.MINIMUM_RESOLUTION) {
-      if (Math.abs(topLat - bottomLat) < Vector.MINIMUM_RESOLUTION)
-        return new GeoDegeneratePoint(planetModel, topLat, leftLon);
-      return new GeoDegenerateVerticalLine(planetModel, topLat, bottomLat, leftLon);
-    }
-    //System.err.println(" not vertical line");
-    if (extent >= Math.PI) {
-      if (Math.abs(topLat - bottomLat) < Vector.MINIMUM_RESOLUTION) {
-        //System.err.println(" wide degenerate line");
-        return new GeoWideDegenerateHorizontalLine(planetModel, topLat, leftLon, rightLon);
-      }
-      if (Math.abs(topLat - Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION) {
-        return new GeoWideNorthRectangle(planetModel, bottomLat, leftLon, rightLon);
-      } else if (Math.abs(bottomLat + Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION) {
-        return new GeoWideSouthRectangle(planetModel, topLat, leftLon, rightLon);
-      }
-      //System.err.println(" wide rect");
-      return new GeoWideRectangle(planetModel, topLat, bottomLat, leftLon, rightLon);
-    }
-    if (Math.abs(topLat - bottomLat) < Vector.MINIMUM_RESOLUTION) {
-      if (Math.abs(topLat - Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION || Math.abs(topLat + Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION) {
-        return new GeoDegeneratePoint(planetModel, topLat, 0.0);
-      }
-      //System.err.println(" horizontal line");
-      return new GeoDegenerateHorizontalLine(planetModel, topLat, leftLon, rightLon);
-    }
-    if (Math.abs(topLat - Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION) {
-      return new GeoNorthRectangle(planetModel, bottomLat, leftLon, rightLon);
-    } else if (Math.abs(bottomLat + Math.PI * 0.5) <  Vector.MINIMUM_RESOLUTION) {
-      return new GeoSouthRectangle(planetModel, topLat, leftLon, rightLon);
-    }
-    //System.err.println(" rectangle");
-    return new GeoRectangle(planetModel, topLat, bottomLat, leftLon, rightLon);
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseBBox.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseBBox.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseBBox.java
deleted file mode 100644
index f40a0a1..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseBBox.java
+++ /dev/null
@@ -1,72 +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.geo3d;
-
-/**
- * All bounding box shapes can derive from this base class, which furnishes
- * some common code
- *
- * @lucene.internal
- */
-public abstract class GeoBaseBBox extends GeoBaseMembershipShape implements GeoBBox {
-
-  /** Construct, given planet model.
-   *@param planetModel is the planet model.
-   */
-  public GeoBaseBBox(final PlanetModel planetModel) {
-    super(planetModel);
-  }
-
-  // Signals for relationship of edge points to shape
-  
-  /** All edgepoints inside shape */
-  protected final static int ALL_INSIDE = 0;
-  /** Some edgepoints inside shape */
-  protected final static int SOME_INSIDE = 1;
-  /** No edgepoints inside shape */
-  protected final static int NONE_INSIDE = 2;
-
-  /** Determine the relationship between this BBox and the provided
-   * shape's edgepoints.
-   *@param path is the shape.
-   *@return the relationship.
-   */
-  protected int isShapeInsideBBox(final GeoShape path) {
-    final GeoPoint[] pathPoints = path.getEdgePoints();
-    boolean foundOutside = false;
-    boolean foundInside = false;
-    for (GeoPoint p : pathPoints) {
-      if (isWithin(p)) {
-        foundInside = true;
-      } else {
-        foundOutside = true;
-      }
-      if (foundInside && foundOutside) {
-        return SOME_INSIDE;
-      }
-    }
-    if (!foundInside && !foundOutside)
-      return NONE_INSIDE;
-    if (foundInside && !foundOutside)
-      return ALL_INSIDE;
-    if (foundOutside && !foundInside)
-      return NONE_INSIDE;
-    return SOME_INSIDE;
-  }
-
-}
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseCircle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseCircle.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseCircle.java
deleted file mode 100644
index 8c306d7..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseCircle.java
+++ /dev/null
@@ -1,34 +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.geo3d;
-
-/**
- * GeoCircles have all the characteristics of GeoBaseDistanceShapes, plus GeoSizeable.
- *
- * @lucene.experimental
- */
-public abstract class GeoBaseCircle extends GeoBaseDistanceShape implements GeoCircle {
-
-  /** Constructor.
-   *@param planetModel is the planet model to use.
-   */
-  public GeoBaseCircle(final PlanetModel planetModel) {
-    super(planetModel);
-  }
-
-}
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseDistanceShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseDistanceShape.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseDistanceShape.java
deleted file mode 100644
index 1c8306a..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseDistanceShape.java
+++ /dev/null
@@ -1,56 +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.geo3d;
-
-/**
- * Distance shapes have capabilities of both geohashing and distance
- * computation (which also includes point membership determination).
- *
- * @lucene.experimental
- */
-public abstract class GeoBaseDistanceShape extends GeoBaseMembershipShape implements GeoDistanceShape {
-
-  /** Constructor.
-   *@param planetModel is the planet model to use.
-   */
-  public GeoBaseDistanceShape(final PlanetModel planetModel) {
-    super(planetModel);
-  }
-
-  @Override
-  public boolean isWithin(Vector point) {
-    return isWithin(point.x, point.y, point.z);
-  }
-
-  @Override
-  public double computeDistance(final DistanceStyle distanceStyle, final GeoPoint point) {
-    return computeDistance(distanceStyle, point.x, point.y, point.z);
-  }
-
-  @Override
-  public double computeDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    if (!isWithin(x,y,z)) {
-      return Double.MAX_VALUE;
-    }
-    return distance(distanceStyle, x, y, z);
-  }
-
-  /** Called by a {@code computeDistance} method if X/Y/Z is not within this shape. */
-  protected abstract double distance(final DistanceStyle distanceStyle, final double x, final double y, final double z);
-
-}
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseMembershipShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseMembershipShape.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseMembershipShape.java
deleted file mode 100644
index a6bba8f..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseMembershipShape.java
+++ /dev/null
@@ -1,56 +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.geo3d;
-
-/**
- * Membership shapes have capabilities of both geohashing and membership
- * determination.  This is a useful baseclass for them.
- *
- * @lucene.experimental
- */
-public abstract class GeoBaseMembershipShape extends GeoBaseShape implements GeoMembershipShape {
-
-  /** Constructor.
-   *@param planetModel is the planet model to use.
-   */
-  public GeoBaseMembershipShape(final PlanetModel planetModel) {
-    super(planetModel);
-  }
-
-  @Override
-  public boolean isWithin(Vector point) {
-    return isWithin(point.x, point.y, point.z);
-  }
-
-  @Override
-  public double computeOutsideDistance(final DistanceStyle distanceStyle, final GeoPoint point) {
-    return computeOutsideDistance(distanceStyle, point.x, point.y, point.z);
-  }
-
-  @Override
-  public double computeOutsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    if (isWithin(x,y,z)) {
-      return 0.0;
-    }
-    return outsideDistance(distanceStyle, x,y,z);
-  }
-
-  /** Called by a {@code computeOutsideDistance} method if X/Y/Z is not within this shape. */
-  protected abstract double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z);
-
-}
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBasePolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBasePolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBasePolygon.java
deleted file mode 100644
index 50ad0dc..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBasePolygon.java
+++ /dev/null
@@ -1,34 +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.geo3d;
-
-/**
- * GeoBasePolygon objects are the base class of most GeoPolygon objects.
- *
- * @lucene.experimental
- */
-public abstract class GeoBasePolygon extends GeoBaseMembershipShape implements GeoPolygon {
-
-  /** Constructor.
-   *@param planetModel is the planet model to use.
-   */
-  public GeoBasePolygon(final PlanetModel planetModel) {
-    super(planetModel);
-  }
-
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseShape.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseShape.java
deleted file mode 100644
index 146cfe8..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseShape.java
+++ /dev/null
@@ -1,59 +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.geo3d;
-
-/**
- * Base extended shape object.
- *
- * @lucene.internal
- */
-public abstract class GeoBaseShape extends BasePlanetObject implements GeoShape {
-
-  /** Constructor.
-   *@param planetModel is the planet model to use.
-   */
-  public GeoBaseShape(final PlanetModel planetModel) {
-    super(planetModel);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    if (isWithin(planetModel.NORTH_POLE)) {
-      bounds.noTopLatitudeBound().noLongitudeBound()
-        .addPoint(planetModel.NORTH_POLE);
-    }
-    if (isWithin(planetModel.SOUTH_POLE)) {
-      bounds.noBottomLatitudeBound().noLongitudeBound()
-        .addPoint(planetModel.SOUTH_POLE);
-    }
-    if (isWithin(planetModel.MIN_X_POLE)) {
-      bounds.addPoint(planetModel.MIN_X_POLE);
-    }
-    if (isWithin(planetModel.MAX_X_POLE)) {
-      bounds.addPoint(planetModel.MAX_X_POLE);
-    }
-    if (isWithin(planetModel.MIN_Y_POLE)) {
-      bounds.addPoint(planetModel.MIN_Y_POLE);
-    }
-    if (isWithin(planetModel.MAX_Y_POLE)) {
-      bounds.addPoint(planetModel.MAX_Y_POLE);
-    }
-  }
-
-}
-
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCircle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCircle.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCircle.java
deleted file mode 100755
index 154cdc4..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCircle.java
+++ /dev/null
@@ -1,25 +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.geo3d;
-
-/**
- * Interface describing circular area with a center and radius.
- *
- * @lucene.experimental
- */
-public interface GeoCircle extends GeoDistanceShape, GeoSizeable {
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCircleFactory.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCircleFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCircleFactory.java
deleted file mode 100644
index 2bb8ffc..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCircleFactory.java
+++ /dev/null
@@ -1,43 +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.geo3d;
-
-/**
- * Class which constructs a GeoCircle representing an arbitrary circle.
- *
- * @lucene.experimental
- */
-public class GeoCircleFactory {
-  private GeoCircleFactory() {
-  }
-
-  /**
-   * Create a GeoCircle of the right kind given the specified bounds.
-   * @param planetModel is the planet model.
-   * @param latitude is the center latitude.
-   * @param longitude is the center longitude.
-   * @param radius is the radius angle.
-   * @return a GeoCircle corresponding to what was specified.
-   */
-  public static GeoCircle makeGeoCircle(final PlanetModel planetModel, final double latitude, final double longitude, final double radius) {
-    if (radius < Vector.MINIMUM_RESOLUTION) {
-      return new GeoDegeneratePoint(planetModel, latitude, longitude);
-    }
-    return new GeoStandardCircle(planetModel, latitude, longitude, radius);
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCompositeMembershipShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCompositeMembershipShape.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCompositeMembershipShape.java
deleted file mode 100755
index 25bdda0..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCompositeMembershipShape.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.geo3d;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * GeoComposite is a set of GeoMembershipShape's, treated as a unit.
- *
- * @lucene.experimental
- */
-public class GeoCompositeMembershipShape implements GeoMembershipShape {
-  /** The list of shapes. */
-  protected final List<GeoMembershipShape> shapes = new ArrayList<GeoMembershipShape>();
-
-  /** Constructor.
-   */
-  public GeoCompositeMembershipShape() {
-  }
-
-  /**
-   * Add a shape to the composite.
-   *@param shape is the shape to add.
-   */
-  public void addShape(final GeoMembershipShape shape) {
-    shapes.add(shape);
-  }
-
-  @Override
-  public boolean isWithin(final Vector point) {
-    return isWithin(point.x, point.y, point.z);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    for (GeoMembershipShape shape : shapes) {
-      if (shape.isWithin(x, y, z))
-        return true;
-    }
-    return false;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return shapes.get(0).getEdgePoints();
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    for (GeoMembershipShape shape : shapes) {
-      if (shape.intersects(p, notablePoints, bounds))
-        return true;
-    }
-    return false;
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    for (GeoMembershipShape shape : shapes) {
-      shape.getBounds(bounds);
-    }
-  }
-
-  @Override
-  public double computeOutsideDistance(final DistanceStyle distanceStyle, final GeoPoint point) {
-    return computeOutsideDistance(distanceStyle, point.x, point.y, point.z);
-  }
-
-  @Override
-  public double computeOutsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    if (isWithin(x,y,z))
-      return 0.0;
-    double distance = Double.MAX_VALUE;
-    for (GeoMembershipShape shape : shapes) {
-      final double normalDistance = shape.computeOutsideDistance(distanceStyle, x, y, z);
-      if (normalDistance < distance) {
-        distance = normalDistance;
-      }
-    }
-    return distance;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoCompositeMembershipShape))
-      return false;
-    GeoCompositeMembershipShape other = (GeoCompositeMembershipShape) o;
-
-    return super.equals(o) && shapes.equals(other.shapes);
-  }
-
-  @Override
-  public int hashCode() {
-    return super.hashCode() * 31 + shapes.hashCode();//TODO cache
-  }
-
-  @Override
-  public String toString() {
-    return "GeoCompositeMembershipShape: {" + shapes + '}';
-  }
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCompositePolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCompositePolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCompositePolygon.java
deleted file mode 100644
index b537590..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCompositePolygon.java
+++ /dev/null
@@ -1,31 +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.geo3d;
-
-/**
- * GeoCompositePolygon is a specific implementation of GeoMembershipShape, which implements GeoPolygon explicitly.
- *
- * @lucene.experimental
- */
-public class GeoCompositePolygon extends GeoCompositeMembershipShape implements GeoPolygon {
-  /** Constructor.
-   */
-  public GeoCompositePolygon() {
-  }
-
-}
-  


[32/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 3a31a8c)

Posted by ds...@apache.org.
LUCENE-7056: Geo3D package re-org
(cherry picked from commit 3a31a8c)


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/0a1951be
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/0a1951be
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/0a1951be

Branch: refs/heads/branch_6_0
Commit: 0a1951bef2ca7e18993ca167ff0c20f2e13e3c84
Parents: 88789aa
Author: David Smiley <ds...@apache.org>
Authored: Mon Mar 7 20:11:25 2016 -0500
Committer: David Smiley <ds...@apache.org>
Committed: Mon Mar 7 20:11:26 2016 -0500

----------------------------------------------------------------------
 lucene/CHANGES.txt                              |    2 +
 .../lucene/spatial/spatial4j/Geo3dShape.java    |   12 +-
 .../lucene/spatial/spatial4j/Geo3dRptTest.java  |   14 +-
 .../Geo3dShapeRectRelationTestCase.java         |   18 +-
 .../Geo3dShapeSphereModelRectRelationTest.java  |   16 +-
 .../Geo3dShapeWGS84ModelRectRelationTest.java   |   16 +-
 .../spatial/spatial4j/geo3d/GeoPointTest.java   |   80 -
 .../org/apache/lucene/geo3d/ArcDistance.java    |   56 -
 .../apache/lucene/geo3d/BasePlanetObject.java   |   57 -
 .../org/apache/lucene/geo3d/BaseXYZSolid.java   |  167 --
 .../java/org/apache/lucene/geo3d/Bounds.java    |  113 --
 .../org/apache/lucene/geo3d/DistanceStyle.java  |   83 -
 .../org/apache/lucene/geo3d/Geo3DPoint.java     |  112 --
 .../java/org/apache/lucene/geo3d/Geo3DUtil.java |   59 -
 .../java/org/apache/lucene/geo3d/GeoArea.java   |   67 -
 .../org/apache/lucene/geo3d/GeoAreaFactory.java |   55 -
 .../java/org/apache/lucene/geo3d/GeoBBox.java   |   36 -
 .../org/apache/lucene/geo3d/GeoBBoxFactory.java |  111 --
 .../org/apache/lucene/geo3d/GeoBaseBBox.java    |   72 -
 .../org/apache/lucene/geo3d/GeoBaseCircle.java  |   34 -
 .../lucene/geo3d/GeoBaseDistanceShape.java      |   56 -
 .../lucene/geo3d/GeoBaseMembershipShape.java    |   56 -
 .../org/apache/lucene/geo3d/GeoBasePolygon.java |   34 -
 .../org/apache/lucene/geo3d/GeoBaseShape.java   |   59 -
 .../java/org/apache/lucene/geo3d/GeoCircle.java |   25 -
 .../apache/lucene/geo3d/GeoCircleFactory.java   |   43 -
 .../geo3d/GeoCompositeMembershipShape.java      |  117 --
 .../lucene/geo3d/GeoCompositePolygon.java       |   31 -
 .../apache/lucene/geo3d/GeoConvexPolygon.java   |  288 ---
 .../geo3d/GeoDegenerateHorizontalLine.java      |  215 ---
 .../lucene/geo3d/GeoDegenerateLatitudeZone.java |  138 --
 .../geo3d/GeoDegenerateLongitudeSlice.java      |  153 --
 .../apache/lucene/geo3d/GeoDegeneratePoint.java |  135 --
 .../lucene/geo3d/GeoDegenerateVerticalLine.java |  205 ---
 .../org/apache/lucene/geo3d/GeoDistance.java    |   59 -
 .../apache/lucene/geo3d/GeoDistanceShape.java   |   27 -
 .../apache/lucene/geo3d/GeoLatitudeZone.java    |  198 ---
 .../apache/lucene/geo3d/GeoLongitudeSlice.java  |  204 ---
 .../apache/lucene/geo3d/GeoMembershipShape.java |   27 -
 .../lucene/geo3d/GeoNorthLatitudeZone.java      |  165 --
 .../apache/lucene/geo3d/GeoNorthRectangle.java  |  263 ---
 .../apache/lucene/geo3d/GeoOutsideDistance.java |   55 -
 .../java/org/apache/lucene/geo3d/GeoPath.java   |  797 ---------
 .../java/org/apache/lucene/geo3d/GeoPoint.java  |  193 --
 .../org/apache/lucene/geo3d/GeoPolygon.java     |   26 -
 .../apache/lucene/geo3d/GeoPolygonFactory.java  |  187 --
 .../org/apache/lucene/geo3d/GeoRectangle.java   |  288 ---
 .../java/org/apache/lucene/geo3d/GeoShape.java  |   63 -
 .../org/apache/lucene/geo3d/GeoSizeable.java    |   40 -
 .../lucene/geo3d/GeoSouthLatitudeZone.java      |  168 --
 .../apache/lucene/geo3d/GeoSouthRectangle.java  |  259 ---
 .../apache/lucene/geo3d/GeoStandardCircle.java  |  168 --
 .../geo3d/GeoWideDegenerateHorizontalLine.java  |  238 ---
 .../lucene/geo3d/GeoWideLongitudeSlice.java     |  208 ---
 .../lucene/geo3d/GeoWideNorthRectangle.java     |  286 ---
 .../apache/lucene/geo3d/GeoWideRectangle.java   |  319 ----
 .../lucene/geo3d/GeoWideSouthRectangle.java     |  284 ---
 .../java/org/apache/lucene/geo3d/GeoWorld.java  |  106 --
 .../org/apache/lucene/geo3d/LatLonBounds.java   |  322 ----
 .../org/apache/lucene/geo3d/LinearDistance.java |   56 -
 .../lucene/geo3d/LinearSquaredDistance.java     |   56 -
 .../org/apache/lucene/geo3d/Membership.java     |   46 -
 .../org/apache/lucene/geo3d/NormalDistance.java |   56 -
 .../lucene/geo3d/NormalSquaredDistance.java     |   56 -
 .../src/java/org/apache/lucene/geo3d/Plane.java | 1657 ------------------
 .../org/apache/lucene/geo3d/PlanetModel.java    |  277 ---
 .../lucene/geo3d/PointInGeo3DShapeQuery.java    |  210 ---
 .../org/apache/lucene/geo3d/SidedPlane.java     |  175 --
 .../apache/lucene/geo3d/StandardXYZSolid.java   |  417 -----
 .../src/java/org/apache/lucene/geo3d/Tools.java |   41 -
 .../java/org/apache/lucene/geo3d/Vector.java    |  378 ----
 .../java/org/apache/lucene/geo3d/XYZBounds.java |  267 ---
 .../java/org/apache/lucene/geo3d/XYZSolid.java  |   26 -
 .../apache/lucene/geo3d/XYZSolidFactory.java    |   67 -
 .../java/org/apache/lucene/geo3d/XYdZSolid.java |  213 ---
 .../java/org/apache/lucene/geo3d/XdYZSolid.java |  212 ---
 .../org/apache/lucene/geo3d/XdYdZSolid.java     |  138 --
 .../java/org/apache/lucene/geo3d/dXYZSolid.java |  216 ---
 .../org/apache/lucene/geo3d/dXYdZSolid.java     |  138 --
 .../org/apache/lucene/geo3d/dXdYZSolid.java     |  138 --
 .../org/apache/lucene/geo3d/dXdYdZSolid.java    |  146 --
 .../org/apache/lucene/geo3d/package-info.java   |   21 -
 .../org/apache/lucene/spatial3d/Geo3DPoint.java |  114 ++
 .../org/apache/lucene/spatial3d/Geo3DUtil.java  |   59 +
 .../spatial3d/PointInGeo3DShapeQuery.java       |  215 +++
 .../lucene/spatial3d/geom/ArcDistance.java      |   56 +
 .../lucene/spatial3d/geom/BasePlanetObject.java |   57 +
 .../lucene/spatial3d/geom/BaseXYZSolid.java     |  167 ++
 .../apache/lucene/spatial3d/geom/Bounds.java    |  113 ++
 .../lucene/spatial3d/geom/DistanceStyle.java    |   83 +
 .../apache/lucene/spatial3d/geom/GeoArea.java   |   67 +
 .../lucene/spatial3d/geom/GeoAreaFactory.java   |   55 +
 .../apache/lucene/spatial3d/geom/GeoBBox.java   |   36 +
 .../lucene/spatial3d/geom/GeoBBoxFactory.java   |  111 ++
 .../lucene/spatial3d/geom/GeoBaseBBox.java      |   72 +
 .../lucene/spatial3d/geom/GeoBaseCircle.java    |   34 +
 .../spatial3d/geom/GeoBaseDistanceShape.java    |   56 +
 .../spatial3d/geom/GeoBaseMembershipShape.java  |   56 +
 .../lucene/spatial3d/geom/GeoBasePolygon.java   |   34 +
 .../lucene/spatial3d/geom/GeoBaseShape.java     |   59 +
 .../apache/lucene/spatial3d/geom/GeoCircle.java |   25 +
 .../lucene/spatial3d/geom/GeoCircleFactory.java |   43 +
 .../geom/GeoCompositeMembershipShape.java       |  117 ++
 .../spatial3d/geom/GeoCompositePolygon.java     |   31 +
 .../lucene/spatial3d/geom/GeoConvexPolygon.java |  288 +++
 .../geom/GeoDegenerateHorizontalLine.java       |  215 +++
 .../geom/GeoDegenerateLatitudeZone.java         |  138 ++
 .../geom/GeoDegenerateLongitudeSlice.java       |  153 ++
 .../spatial3d/geom/GeoDegeneratePoint.java      |  135 ++
 .../geom/GeoDegenerateVerticalLine.java         |  205 +++
 .../lucene/spatial3d/geom/GeoDistance.java      |   59 +
 .../lucene/spatial3d/geom/GeoDistanceShape.java |   27 +
 .../lucene/spatial3d/geom/GeoLatitudeZone.java  |  198 +++
 .../spatial3d/geom/GeoLongitudeSlice.java       |  204 +++
 .../spatial3d/geom/GeoMembershipShape.java      |   27 +
 .../spatial3d/geom/GeoNorthLatitudeZone.java    |  165 ++
 .../spatial3d/geom/GeoNorthRectangle.java       |  263 +++
 .../spatial3d/geom/GeoOutsideDistance.java      |   55 +
 .../apache/lucene/spatial3d/geom/GeoPath.java   |  797 +++++++++
 .../apache/lucene/spatial3d/geom/GeoPoint.java  |  193 ++
 .../lucene/spatial3d/geom/GeoPolygon.java       |   26 +
 .../spatial3d/geom/GeoPolygonFactory.java       |  187 ++
 .../lucene/spatial3d/geom/GeoRectangle.java     |  288 +++
 .../apache/lucene/spatial3d/geom/GeoShape.java  |   63 +
 .../lucene/spatial3d/geom/GeoSizeable.java      |   40 +
 .../spatial3d/geom/GeoSouthLatitudeZone.java    |  168 ++
 .../spatial3d/geom/GeoSouthRectangle.java       |  259 +++
 .../spatial3d/geom/GeoStandardCircle.java       |  168 ++
 .../geom/GeoWideDegenerateHorizontalLine.java   |  238 +++
 .../spatial3d/geom/GeoWideLongitudeSlice.java   |  208 +++
 .../spatial3d/geom/GeoWideNorthRectangle.java   |  286 +++
 .../lucene/spatial3d/geom/GeoWideRectangle.java |  319 ++++
 .../spatial3d/geom/GeoWideSouthRectangle.java   |  284 +++
 .../apache/lucene/spatial3d/geom/GeoWorld.java  |  106 ++
 .../lucene/spatial3d/geom/LatLonBounds.java     |  322 ++++
 .../lucene/spatial3d/geom/LinearDistance.java   |   56 +
 .../spatial3d/geom/LinearSquaredDistance.java   |   56 +
 .../lucene/spatial3d/geom/Membership.java       |   46 +
 .../lucene/spatial3d/geom/NormalDistance.java   |   56 +
 .../spatial3d/geom/NormalSquaredDistance.java   |   56 +
 .../org/apache/lucene/spatial3d/geom/Plane.java | 1657 ++++++++++++++++++
 .../lucene/spatial3d/geom/PlanetModel.java      |  277 +++
 .../lucene/spatial3d/geom/SidedPlane.java       |  175 ++
 .../lucene/spatial3d/geom/StandardXYZSolid.java |  417 +++++
 .../org/apache/lucene/spatial3d/geom/Tools.java |   41 +
 .../apache/lucene/spatial3d/geom/Vector.java    |  378 ++++
 .../apache/lucene/spatial3d/geom/XYZBounds.java |  267 +++
 .../apache/lucene/spatial3d/geom/XYZSolid.java  |   26 +
 .../lucene/spatial3d/geom/XYZSolidFactory.java  |   67 +
 .../apache/lucene/spatial3d/geom/XYdZSolid.java |  213 +++
 .../apache/lucene/spatial3d/geom/XdYZSolid.java |  212 +++
 .../lucene/spatial3d/geom/XdYdZSolid.java       |  138 ++
 .../apache/lucene/spatial3d/geom/dXYZSolid.java |  216 +++
 .../lucene/spatial3d/geom/dXYdZSolid.java       |  138 ++
 .../lucene/spatial3d/geom/dXdYZSolid.java       |  138 ++
 .../lucene/spatial3d/geom/dXdYdZSolid.java      |  146 ++
 .../lucene/spatial3d/geom/package-info.java     |   22 +
 .../apache/lucene/spatial3d/package-info.java   |   21 +
 lucene/spatial3d/src/java/overview.html         |    3 +-
 .../org/apache/lucene/geo3d/GeoBBoxTest.java    |  364 ----
 .../org/apache/lucene/geo3d/GeoCircleTest.java  |  415 -----
 .../lucene/geo3d/GeoConvexPolygonTest.java      |   91 -
 .../org/apache/lucene/geo3d/GeoModelTest.java   |  110 --
 .../org/apache/lucene/geo3d/GeoPathTest.java    |  270 ---
 .../org/apache/lucene/geo3d/GeoPolygonTest.java |  165 --
 .../test/org/apache/lucene/geo3d/PlaneTest.java |   64 -
 .../org/apache/lucene/geo3d/TestGeo3DPoint.java |  801 ---------
 .../org/apache/lucene/geo3d/XYZSolidTest.java   |  220 ---
 .../apache/lucene/spatial3d/TestGeo3DPoint.java |  810 +++++++++
 .../lucene/spatial3d/geom/GeoBBoxTest.java      |  364 ++++
 .../lucene/spatial3d/geom/GeoCircleTest.java    |  410 +++++
 .../spatial3d/geom/GeoConvexPolygonTest.java    |   91 +
 .../lucene/spatial3d/geom/GeoModelTest.java     |  110 ++
 .../lucene/spatial3d/geom/GeoPathTest.java      |  270 +++
 .../lucene/spatial3d/geom/GeoPointTest.java     |   77 +
 .../lucene/spatial3d/geom/GeoPolygonTest.java   |  165 ++
 .../apache/lucene/spatial3d/geom/PlaneTest.java |   64 +
 .../lucene/spatial3d/geom/XYZSolidTest.java     |  220 +++
 178 files changed, 15186 insertions(+), 15153 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/CHANGES.txt
----------------------------------------------------------------------
diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index 60c088c..c14019b 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -118,6 +118,8 @@ API Changes
 * LUCENE-7072: Geo3DPoint always uses WGS84 planet model.
   (Robert Muir, Mike McCandless)
 
+* LUCENE-7056: Geo3D classes are in different packages now. (David Smiley)
+
 Optimizations
 
 * LUCENE-6891: Use prefix coding when writing points in 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dShape.java b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dShape.java
index 518fb32..9fa6d8e 100644
--- a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dShape.java
+++ b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dShape.java
@@ -23,12 +23,12 @@ import org.locationtech.spatial4j.shape.Rectangle;
 import org.locationtech.spatial4j.shape.Shape;
 import org.locationtech.spatial4j.shape.SpatialRelation;
 import org.locationtech.spatial4j.shape.impl.RectangleImpl;
-import org.apache.lucene.geo3d.LatLonBounds;
-import org.apache.lucene.geo3d.GeoArea;
-import org.apache.lucene.geo3d.GeoAreaFactory;
-import org.apache.lucene.geo3d.GeoPoint;
-import org.apache.lucene.geo3d.GeoShape;
-import org.apache.lucene.geo3d.PlanetModel;
+import org.apache.lucene.spatial3d.geom.LatLonBounds;
+import org.apache.lucene.spatial3d.geom.GeoArea;
+import org.apache.lucene.spatial3d.geom.GeoAreaFactory;
+import org.apache.lucene.spatial3d.geom.GeoPoint;
+import org.apache.lucene.spatial3d.geom.GeoShape;
+import org.apache.lucene.spatial3d.geom.PlanetModel;
 
 /**
  * A Spatial4j Shape wrapping a {@link GeoShape} ("Geo3D") -- a 3D planar geometry based Spatial4j Shape implementation.

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/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
index d26bb29..e62b857 100644
--- 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
@@ -32,13 +32,13 @@ 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.apache.lucene.spatial3d.geom.GeoBBoxFactory;
+import org.apache.lucene.spatial3d.geom.GeoStandardCircle;
+import org.apache.lucene.spatial3d.geom.GeoPath;
+import org.apache.lucene.spatial3d.geom.GeoPoint;
+import org.apache.lucene.spatial3d.geom.GeoPolygonFactory;
+import org.apache.lucene.spatial3d.geom.GeoShape;
+import org.apache.lucene.spatial3d.geom.PlanetModel;
 import org.junit.Test;
 
 import static org.locationtech.spatial4j.distance.DistanceUtils.DEGREES_TO_RADIANS;

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/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
index 134b8c7..d58985f 100644
--- 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
@@ -25,15 +25,15 @@ import org.locationtech.spatial4j.distance.DistanceUtils;
 import org.locationtech.spatial4j.shape.Circle;
 import org.locationtech.spatial4j.shape.Point;
 import org.locationtech.spatial4j.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.apache.lucene.spatial3d.geom.LatLonBounds;
+import org.apache.lucene.spatial3d.geom.GeoBBox;
+import org.apache.lucene.spatial3d.geom.GeoBBoxFactory;
+import org.apache.lucene.spatial3d.geom.GeoStandardCircle;
+import org.apache.lucene.spatial3d.geom.GeoPath;
+import org.apache.lucene.spatial3d.geom.GeoPoint;
+import org.apache.lucene.spatial3d.geom.GeoPolygonFactory;
+import org.apache.lucene.spatial3d.geom.GeoShape;
+import org.apache.lucene.spatial3d.geom.PlanetModel;
 import org.junit.Rule;
 import org.junit.Test;
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/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
index 2d95823..3bce480 100644
--- 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
@@ -20,14 +20,14 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.locationtech.spatial4j.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.apache.lucene.spatial3d.geom.GeoArea;
+import org.apache.lucene.spatial3d.geom.GeoBBox;
+import org.apache.lucene.spatial3d.geom.GeoBBoxFactory;
+import org.apache.lucene.spatial3d.geom.GeoStandardCircle;
+import org.apache.lucene.spatial3d.geom.GeoPoint;
+import org.apache.lucene.spatial3d.geom.GeoPolygonFactory;
+import org.apache.lucene.spatial3d.geom.GeoShape;
+import org.apache.lucene.spatial3d.geom.PlanetModel;
 import org.junit.Test;
 
 public class Geo3dShapeSphereModelRectRelationTest extends Geo3dShapeRectRelationTestCase {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/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
index 3b026c3..b59d7df 100644
--- 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
@@ -16,14 +16,14 @@
  */
 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.apache.lucene.spatial3d.geom.GeoArea;
+import org.apache.lucene.spatial3d.geom.GeoBBox;
+import org.apache.lucene.spatial3d.geom.GeoBBoxFactory;
+import org.apache.lucene.spatial3d.geom.GeoCircle;
+import org.apache.lucene.spatial3d.geom.GeoStandardCircle;
+import org.apache.lucene.spatial3d.geom.GeoPath;
+import org.apache.lucene.spatial3d.geom.GeoPoint;
+import org.apache.lucene.spatial3d.geom.PlanetModel;
 import org.junit.Test;
 
 public class Geo3dShapeWGS84ModelRectRelationTest extends Geo3dShapeRectRelationTestCase {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/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
deleted file mode 100644
index 4446474..0000000
--- a/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/geo3d/GeoPointTest.java
+++ /dev/null
@@ -1,80 +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.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 org.locationtech.spatial4j.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/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/ArcDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/ArcDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/ArcDistance.java
deleted file mode 100644
index c49fd1f..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/ArcDistance.java
+++ /dev/null
@@ -1,56 +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.geo3d;
-
-/**
- * Arc distance computation style.
- *
- * @lucene.experimental
- */
-public class ArcDistance implements DistanceStyle {
-  
-  /** An instance of the ArcDistance DistanceStyle. */
-  public final static ArcDistance INSTANCE = new ArcDistance();
-  
-  /** Constructor.
-   */
-  public ArcDistance() {
-  }
-  
-  @Override
-  public double computeDistance(final GeoPoint point1, final GeoPoint point2) {
-    return point1.arcDistance(point2);
-  }
-  
-  @Override
-  public double computeDistance(final GeoPoint point1, final double x2, final double y2, final double z2) {
-    return point1.arcDistance(x2,y2,z2);
-  }
-
-  @Override
-  public double computeDistance(final PlanetModel planetModel, final Plane plane, final GeoPoint point, final Membership... bounds) {
-    return plane.arcDistance(planetModel, point, bounds);
-  }
-  
-  @Override
-  public double computeDistance(final PlanetModel planetModel, final Plane plane, final double x, final double y, final double z, final Membership... bounds) {
-    return plane.arcDistance(planetModel, x,y,z, bounds);
-  }
-
-}
-
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/BasePlanetObject.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/BasePlanetObject.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/BasePlanetObject.java
deleted file mode 100644
index c64b974..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/BasePlanetObject.java
+++ /dev/null
@@ -1,57 +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.geo3d;
-
-/**
- * All Geo3D shapes can derive from this base class, which furnishes
- * some common code
- *
- * @lucene.internal
- */
-public abstract class BasePlanetObject {
-
-  /** This is the planet model embedded in all objects derived from this
-   * class. */
-  protected final PlanetModel planetModel;
-  
-  /** Constructor creating class instance given a planet model.
-   * @param planetModel is the planet model.
-   */
-  public BasePlanetObject(final PlanetModel planetModel) {
-    this.planetModel = planetModel;
-  }
-
-  /** Returns the {@link PlanetModel} provided when this shape was created. */
-  public PlanetModel getPlanetModel() {
-    return planetModel;
-  }
-  
-  @Override
-  public int hashCode() {
-    return planetModel.hashCode();
-  }
-  
-  @Override
-  public boolean equals(final Object o) {
-    if (!(o instanceof BasePlanetObject))
-      return false;
-    return planetModel.equals(((BasePlanetObject)o).planetModel);
-  }
-}
-
-
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/BaseXYZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/BaseXYZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/BaseXYZSolid.java
deleted file mode 100644
index 52bd5da..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/BaseXYZSolid.java
+++ /dev/null
@@ -1,167 +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.geo3d;
-
-/**
- * Base class of a family of 3D rectangles, bounded on six sides by X,Y,Z limits
- *
- * @lucene.internal
- */
-public abstract class BaseXYZSolid extends BasePlanetObject implements XYZSolid {
-
-  /** Unit vector in x */
-  protected static final Vector xUnitVector = new Vector(1.0, 0.0, 0.0);
-  /** Unit vector in y */
-  protected static final Vector yUnitVector = new Vector(0.0, 1.0, 0.0);
-  /** Unit vector in z */
-  protected static final Vector zUnitVector = new Vector(0.0, 0.0, 1.0);
-  
-  /** Vertical plane normal to x unit vector passing through origin */
-  protected static final Plane xVerticalPlane = new Plane(0.0, 1.0, 0.0, 0.0);
-  /** Vertical plane normal to y unit vector passing through origin */
-  protected static final Plane yVerticalPlane = new Plane(1.0, 0.0, 0.0, 0.0);
-
-  /** Empty point vector */
-  protected static final GeoPoint[] EMPTY_POINTS = new GeoPoint[0];
-  
-  /**
-   * Base solid constructor.
-   *@param planetModel is the planet model.
-   */
-  public BaseXYZSolid(final PlanetModel planetModel) {
-    super(planetModel);
-  }
-  
-  /** Construct a single array from a number of individual arrays.
-   * @param pointArrays is the array of point arrays.
-   * @return the single unified array.
-   */
-  protected static GeoPoint[] glueTogether(final GeoPoint[]... pointArrays) {
-    int count = 0;
-    for (final GeoPoint[] pointArray : pointArrays) {
-      count += pointArray.length;
-    }
-    final GeoPoint[] rval = new GeoPoint[count];
-    count = 0;
-    for (final GeoPoint[] pointArray : pointArrays) {
-      for (final GeoPoint point : pointArray) {
-        rval[count++] = point;
-      }
-    }
-    return rval;
-  }
-  
-  @Override
-  public boolean isWithin(final Vector point) {
-    return isWithin(point.x, point.y, point.z);
-  }
-  
-  @Override
-  public abstract boolean isWithin(final double x, final double y, final double z);
-  
-  // Signals for relationship of edge points to shape
-  
-  /** All edgepoints inside shape */
-  protected final static int ALL_INSIDE = 0;
-  /** Some edgepoints inside shape */
-  protected final static int SOME_INSIDE = 1;
-  /** No edgepoints inside shape */
-  protected final static int NONE_INSIDE = 2;
-  /** No edgepoints at all (means a shape that is the whole world) */
-  protected final static int NO_EDGEPOINTS = 3;
-
-  /** Determine the relationship between this area and the provided
-   * shape's edgepoints.
-   *@param path is the shape.
-   *@return the relationship.
-   */
-  protected int isShapeInsideArea(final GeoShape path) {
-    final GeoPoint[] pathPoints = path.getEdgePoints();
-    if (pathPoints.length == 0)
-      return NO_EDGEPOINTS;
-    boolean foundOutside = false;
-    boolean foundInside = false;
-    for (final GeoPoint p : pathPoints) {
-      if (isWithin(p)) {
-        foundInside = true;
-      } else {
-        foundOutside = true;
-      }
-      if (foundInside && foundOutside) {
-        return SOME_INSIDE;
-      }
-    }
-    if (!foundInside && !foundOutside)
-      return NONE_INSIDE;
-    if (foundInside && !foundOutside)
-      return ALL_INSIDE;
-    if (foundOutside && !foundInside)
-      return NONE_INSIDE;
-    return SOME_INSIDE;
-  }
-
-  /** Determine the relationship between a shape and this area's
-   * edgepoints.
-   *@param path is the shape.
-   *@return the relationship.
-   */
-  protected int isAreaInsideShape(final GeoShape path) {
-    final GeoPoint[] edgePoints = getEdgePoints();
-    if (edgePoints.length == 0) {
-      return NO_EDGEPOINTS;
-    }
-    boolean foundOutside = false;
-    boolean foundInside = false;
-    for (final GeoPoint p : edgePoints) {
-      if (path.isWithin(p)) {
-        foundInside = true;
-      } else {
-        foundOutside = true;
-      }
-      if (foundInside && foundOutside) {
-        return SOME_INSIDE;
-      }
-    }
-    if (!foundInside && !foundOutside)
-      return NONE_INSIDE;
-    if (foundInside && !foundOutside)
-      return ALL_INSIDE;
-    if (foundOutside && !foundInside)
-      return NONE_INSIDE;
-    return SOME_INSIDE;
-  }
-
-  /** Get the edge points for this shape.
-   *@return the edge points.
-   */
-  protected abstract GeoPoint[] getEdgePoints();
-  
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof BaseXYZSolid))
-      return false;
-    BaseXYZSolid other = (BaseXYZSolid) o;
-    return super.equals(other);
-  }
-
-  @Override
-  public int hashCode() {
-    return super.hashCode();
-  }
-
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Bounds.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Bounds.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Bounds.java
deleted file mode 100755
index 6717220..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Bounds.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.geo3d;
-
-/**
- * An interface for accumulating bounds information.
- * The bounds object is initially empty.  Bounding points
- * are then applied by supplying (x,y,z) tuples.  It is also
- * possible to indicate the following edge cases:
- * (1) No longitude bound possible
- * (2) No upper latitude bound possible
- * (3) No lower latitude bound possible
- * When any of these have been applied, further application of
- * points cannot override that decision.
- *
- * @lucene.experimental
- */
-public interface Bounds {
-
-  /** Add a general plane to the bounds description.
-   *@param planetModel is the planet model.
-   *@param plane is the plane.
-   *@param bounds are the membership bounds for points along the arc.
-   */
-  public Bounds addPlane(final PlanetModel planetModel, final Plane plane, final Membership... bounds);
-  
-  /** Add a horizontal plane to the bounds description.
-   * This method should EITHER use the supplied latitude, OR use the supplied
-   * plane, depending on what is most efficient.
-   *@param planetModel is the planet model.
-   *@param latitude is the latitude.
-   *@param horizontalPlane is the plane.
-   *@param bounds are the constraints on the plane.
-   *@return updated Bounds object.
-   */
-  public Bounds addHorizontalPlane(final PlanetModel planetModel,
-    final double latitude,
-    final Plane horizontalPlane,
-    final Membership... bounds);
-    
-  /** Add a vertical plane to the bounds description.
-   * This method should EITHER use the supplied longitude, OR use the supplied
-   * plane, depending on what is most efficient.
-   *@param planetModel is the planet model.
-   *@param longitude is the longitude.
-   *@param verticalPlane is the plane.
-   *@param bounds are the constraints on the plane.
-   *@return updated Bounds object.
-   */
-  public Bounds addVerticalPlane(final PlanetModel planetModel,
-    final double longitude,
-    final Plane verticalPlane,
-    final Membership... bounds);
-
-  /** Add a single point.
-   *@param point is the point.
-   *@return the updated Bounds object.
-   */
-  public Bounds addPoint(final GeoPoint point);
-
-  /** Add an X value.
-   *@param point is the point to take the x value from.
-   *@return the updated object.
-   */
-  public Bounds addXValue(final GeoPoint point);
-
-  /** Add a Y value.
-   *@param point is the point to take the y value from.
-   *@return the updated object.
-   */
-  public Bounds addYValue(final GeoPoint point);
-
-  /** Add a Z value.
-   *@param point is the point to take the z value from.
-   *@return the updated object.
-   */
-  public Bounds addZValue(final GeoPoint point);
-  
-  /** Signal that the shape exceeds Math.PI in longitude.
-   *@return the updated Bounds object.
-   */
-  public Bounds isWide();
-  
-  /** Signal that there is no longitude bound.
-   *@return the updated Bounds object.
-   */
-  public Bounds noLongitudeBound();
-
-  /** Signal that there is no top latitude bound.
-   *@return the updated Bounds object.
-   */
-  public Bounds noTopLatitudeBound();
-
-  /** Signal that there is no bottom latitude bound.
-   *@return the updated Bounds object.
-   */
-  public Bounds noBottomLatitudeBound();
-  
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/DistanceStyle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/DistanceStyle.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/DistanceStyle.java
deleted file mode 100644
index 28056cb..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/DistanceStyle.java
+++ /dev/null
@@ -1,83 +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.geo3d;
-
-/**
- * Distance computation styles, supporting various ways of computing
- * distance to shapes.
- *
- * @lucene.experimental
- */
-public interface DistanceStyle {
-
-  // convenient access to built-in styles:
-
-  /** Arc distance calculator */
-  public static final ArcDistance ARC = ArcDistance.INSTANCE;
-  /** Linear distance calculator */
-  public static final LinearDistance LINEAR = LinearDistance.INSTANCE;
-  /** Linear distance squared calculator */
-  public static final LinearSquaredDistance LINEAR_SQUARED = LinearSquaredDistance.INSTANCE;
-  /** Normal distance calculator */
-  public static final NormalDistance NORMAL = NormalDistance.INSTANCE;
-  /** Normal distance squared calculator */
-  public static final NormalSquaredDistance NORMAL_SQUARED = NormalSquaredDistance.INSTANCE;
-
-  /** Compute the distance from a point to another point.
-   * @param point1 Starting point
-   * @param point2 Final point
-   * @return the distance
-   */
-  public default double computeDistance(final GeoPoint point1, final GeoPoint point2) {
-    return computeDistance(point1, point2.x, point2.y, point2.z);
-  }
-  
-  /** Compute the distance from a point to another point.
-   * @param point1 Starting point
-   * @param x2 Final point x
-   * @param y2 Final point y
-   * @param z2 Final point z
-   * @return the distance
-   */
-  public double computeDistance(final GeoPoint point1, final double x2, final double y2, final double z2);
-
-  /** Compute the distance from a plane to a point.
-   * @param planetModel The planet model
-   * @param plane The plane
-   * @param point The point
-   * @param bounds are the plane bounds
-   * @return the distance
-   */
-  public default double computeDistance(final PlanetModel planetModel, final Plane plane, final GeoPoint point,
-                                        final Membership... bounds) {
-    return computeDistance(planetModel, plane, point.x, point.y, point.z, bounds);
-  }
-  
-  /** Compute the distance from a plane to a point.
-   * @param planetModel The planet model
-   * @param plane The plane
-   * @param x The point x
-   * @param y The point y
-   * @param z The point z
-   * @param bounds are the plane bounds
-   * @return the distance
-   */
-  public double computeDistance(final PlanetModel planetModel, final Plane plane, final double x, final double y, final double z, final Membership... bounds);
-
-}
-
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Geo3DPoint.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Geo3DPoint.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Geo3DPoint.java
deleted file mode 100644
index cde87f3..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Geo3DPoint.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.geo3d;
-
-import org.apache.lucene.document.Field;
-import org.apache.lucene.document.FieldType;
-import org.apache.lucene.search.Query;
-import org.apache.lucene.util.BytesRef;
-import org.apache.lucene.util.NumericUtils;
-import org.apache.lucene.util.RamUsageEstimator;
-
-/**
- * Add this to a document to index lat/lon or x/y/z point, indexed as a 3D point.
- * Multiple values are allowed: just add multiple Geo3DPoint to the document with the
- * same field name.
- * <p>
- * This field defines static factory methods for creating a shape query:
- * <ul>
- *   <li>{@link #newShapeQuery newShapeQuery()} for matching all points inside a specified shape
- * </ul>
- *
- *  @lucene.experimental */
-public final class Geo3DPoint extends Field {
-
-  /** Indexing {@link FieldType}. */
-  public static final FieldType TYPE = new FieldType();
-  static {
-    TYPE.setDimensions(3, Integer.BYTES);
-    TYPE.freeze();
-  }
-
-  /** 
-   * Creates a new Geo3DPoint field with the specified lat, lon (in radians).
-   *
-   * @throws IllegalArgumentException if the field name is null or lat or lon are out of bounds
-   */
-  public Geo3DPoint(String name, double lat, double lon) {
-    super(name, TYPE);
-    // Translate lat/lon to x,y,z:
-    final GeoPoint point = new GeoPoint(PlanetModel.WGS84, lat, lon);
-    fillFieldsData(point.x, point.y, point.z);
-  }
-
-  /** 
-   * Creates a new Geo3DPoint field with the specified x,y,z.
-   *
-   * @throws IllegalArgumentException if the field name is null or lat or lon are out of bounds
-   */
-  public Geo3DPoint(String name, double x, double y, double z) {
-    super(name, TYPE);
-    fillFieldsData(x, y, z);
-  }
-
-  private void fillFieldsData(double x, double y, double z) {
-    byte[] bytes = new byte[12];
-    encodeDimension(x, bytes, 0);
-    encodeDimension(y, bytes, Integer.BYTES);
-    encodeDimension(z, bytes, 2*Integer.BYTES);
-    fieldsData = new BytesRef(bytes);
-  }
-
-  // public helper methods (e.g. for queries)
-  
-  /** Encode single dimension */
-  public static void encodeDimension(double value, byte bytes[], int offset) {
-    NumericUtils.intToSortableBytes(Geo3DUtil.encodeValue(PlanetModel.WGS84.getMaximumMagnitude(), value), bytes, offset);
-  }
-  
-  /** Decode single dimension */
-  public static double decodeDimension(byte value[], int offset) {
-    return Geo3DUtil.decodeValueCenter(PlanetModel.WGS84.getMaximumMagnitude(), NumericUtils.sortableBytesToInt(value, offset));
-  }
-
-  /** Returns a query matching all points inside the provided shape.
-   * 
-   * @param field field name. must not be {@code null}.
-   * @param shape Which {@link GeoShape} to match
-   */
-  public static Query newShapeQuery(String field, GeoShape shape) {
-    return new PointInGeo3DShapeQuery(field, shape);
-  }
-
-  @Override
-  public String toString() {
-    StringBuilder result = new StringBuilder();
-    result.append(getClass().getSimpleName());
-    result.append(" <");
-    result.append(name);
-    result.append(':');
-
-    BytesRef bytes = (BytesRef) fieldsData;
-    result.append(" x=" + decodeDimension(bytes.bytes, bytes.offset));
-    result.append(" y=" + decodeDimension(bytes.bytes, bytes.offset + Integer.BYTES));
-    result.append(" z=" + decodeDimension(bytes.bytes, bytes.offset + 2*Integer.BYTES));
-    result.append('>');
-    return result.toString();
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Geo3DUtil.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Geo3DUtil.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Geo3DUtil.java
deleted file mode 100644
index 34880a1..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Geo3DUtil.java
+++ /dev/null
@@ -1,59 +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.geo3d;
-
-class Geo3DUtil {
-
-  /** Clips the incoming value to the allowed min/max range before encoding, instead of throwing an exception. */
-  public static int encodeValueLenient(double planetMax, double x) {
-    if (x > planetMax) {
-      x = planetMax;
-    } else if (x < -planetMax) {
-      x = -planetMax;
-    }
-    return encodeValue(planetMax, x);
-  }
-
-  public static int encodeValue(double planetMax, double x) {
-    if (x > planetMax) {
-      throw new IllegalArgumentException("value=" + x + " is out-of-bounds (greater than planetMax=" + planetMax + ")");
-    }
-    if (x < -planetMax) {
-      throw new IllegalArgumentException("value=" + x + " is out-of-bounds (less than than -planetMax=" + -planetMax + ")");
-    }
-    long y = Math.round (x * (Integer.MAX_VALUE / planetMax));
-    assert y >= Integer.MIN_VALUE;
-    assert y <= Integer.MAX_VALUE;
-
-    return (int) y;
-  }
-
-  /** Center decode */
-  public static double decodeValueCenter(double planetMax, int x) {
-    return x * (planetMax / Integer.MAX_VALUE);
-  }
-
-  /** More negative decode, at bottom of cell */
-  public static double decodeValueMin(double planetMax, int x) {
-    return (((double)x) - 0.5) * (planetMax / Integer.MAX_VALUE);
-  }
-  
-  /** More positive decode, at top of cell  */
-  public static double decodeValueMax(double planetMax, int x) {
-    return (((double)x) + 0.5) * (planetMax / Integer.MAX_VALUE);
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoArea.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoArea.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoArea.java
deleted file mode 100755
index 424e494..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoArea.java
+++ /dev/null
@@ -1,67 +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.geo3d;
-
-/**
- * A GeoArea represents a standard 2-D breakdown of a part of sphere.  It can
- * be bounded in latitude, or bounded in both latitude and longitude, or not
- * bounded at all.  The purpose of the interface is to describe bounding shapes used for
- * computation of geo hashes.
- *
- * @lucene.experimental
- */
-public interface GeoArea extends Membership {
-  // Since we don't know what each GeoArea's constraints are,
-  // we put the onus on the GeoArea implementation to do the right thing.
-  // This will, of course, rely heavily on methods provided by
-  // the underlying GeoShape class.
-
-  // Relationship values for "getRelationship()"
-  
-  /** The referenced shape CONTAINS this area */
-  public static final int CONTAINS = 0;
-  /** The referenced shape IS WITHIN this area */
-  public static final int WITHIN = 1;
-  /** The referenced shape OVERLAPS this area */
-  public static final int OVERLAPS = 2;
-  /** The referenced shape has no relation to this area */
-  public static final int DISJOINT = 3;
-
-  /**
-   * Find the spatial relationship between a shape and the current geo area.
-   * Note: return value is how the GeoShape relates to the GeoArea, not the
-   * other way around. For example, if this GeoArea is entirely within the
-   * shape, then CONTAINS should be returned.  If the shape is entirely enclosed
-   * by this GeoArea, then WITHIN should be returned.
-   *
-   * It is permissible to return OVERLAPS instead of WITHIN if the shape
-   * intersects with the area at even a single point.  So, a circle inscribed in
-   * a rectangle could return either OVERLAPS or WITHIN, depending on
-   * implementation.  It is not permissible to return CONTAINS or DISJOINT
-   * in this circumstance, however.
-   *
-   * Similarly, it is permissible to return OVERLAPS instead of CONTAINS
-   * under conditions where the shape consists of multiple independent overlapping
-   * subshapes, and the area overlaps one of the subshapes.  It is not permissible
-   * to return WITHIN or DISJOINT in this circumstance, however.
-   *
-   * @param shape is the shape to consider.
-   * @return the relationship, from the perspective of the shape.
-   */
-  public int getRelationship(GeoShape shape);
-}
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoAreaFactory.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoAreaFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoAreaFactory.java
deleted file mode 100755
index 24dd211..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoAreaFactory.java
+++ /dev/null
@@ -1,55 +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.geo3d;
-
-/**
- * Factory for {@link org.apache.lucene.geo3d.GeoArea}.
- *
- * @lucene.experimental
- */
-public class GeoAreaFactory {
-  private GeoAreaFactory() {
-  }
-
-  /**
-   * Create a GeoArea of the right kind given the specified bounds.
-   * @param planetModel is the planet model
-   * @param topLat    is the top latitude
-   * @param bottomLat is the bottom latitude
-   * @param leftLon   is the left longitude
-   * @param rightLon  is the right longitude
-   * @return a GeoArea corresponding to what was specified.
-   */
-  public static GeoArea makeGeoArea(final PlanetModel planetModel, final double topLat, final double bottomLat, final double leftLon, final double rightLon) {
-    return GeoBBoxFactory.makeGeoBBox(planetModel, topLat, bottomLat, leftLon, rightLon);
-  }
-
-  /**
-   * Create a GeoArea of the right kind given (x,y,z) bounds.
-   * @param planetModel is the planet model
-   * @param minX is the min X boundary
-   * @param maxX is the max X boundary
-   * @param minY is the min Y boundary
-   * @param maxY is the max Y boundary
-   * @param minZ is the min Z boundary
-   * @param maxZ is the max Z boundary
-   */
-  public static GeoArea makeGeoArea(final PlanetModel planetModel, final double minX, final double maxX, final double minY, final double maxY, final double minZ, final double maxZ) {
-    return XYZSolidFactory.makeXYZSolid(planetModel, minX, maxX, minY, maxY, minZ, maxZ);
-  }
-  
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBBox.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBBox.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBBox.java
deleted file mode 100755
index 10a2388..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBBox.java
+++ /dev/null
@@ -1,36 +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.geo3d;
-
-/**
- * All bounding box shapes have this interface in common.
- * This describes methods that bounding boxes have above and beyond
- * GeoMembershipShape's.
- *
- * @lucene.experimental
- */
-public interface GeoBBox extends GeoMembershipShape, GeoSizeable, GeoArea {
-
-  /**
-   * Expand box by specified angle.
-   *
-   * @param angle is the angle amount to expand the GeoBBox by.
-   * @return a new GeoBBox.
-   */
-  public GeoBBox expand(double angle);
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBBoxFactory.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBBoxFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBBoxFactory.java
deleted file mode 100755
index 9a02ab9..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBBoxFactory.java
+++ /dev/null
@@ -1,111 +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.geo3d;
-
-/**
- * Factory for {@link org.apache.lucene.geo3d.GeoBBox}.
- *
- * @lucene.experimental
- */
-public class GeoBBoxFactory {
-  private GeoBBoxFactory() {
-  }
-
-  /**
-   * Create a geobbox of the right kind given the specified bounds.
-   *
-   * @param planetModel is the planet model
-   * @param topLat    is the top latitude
-   * @param bottomLat is the bottom latitude
-   * @param leftLon   is the left longitude
-   * @param rightLon  is the right longitude
-   * @return a GeoBBox corresponding to what was specified.
-   */
-  public static GeoBBox makeGeoBBox(final PlanetModel planetModel, double topLat, double bottomLat, double leftLon, double rightLon) {
-    //System.err.println("Making rectangle for topLat="+topLat*180.0/Math.PI+", bottomLat="+bottomLat*180.0/Math.PI+", leftLon="+leftLon*180.0/Math.PI+", rightlon="+rightLon*180.0/Math.PI);
-    if (topLat > Math.PI * 0.5)
-      topLat = Math.PI * 0.5;
-    if (bottomLat < -Math.PI * 0.5)
-      bottomLat = -Math.PI * 0.5;
-    if (leftLon < -Math.PI)
-      leftLon = -Math.PI;
-    if (rightLon > Math.PI)
-      rightLon = Math.PI;
-    if (Math.abs(leftLon + Math.PI) < Vector.MINIMUM_RESOLUTION && Math.abs(rightLon - Math.PI) < Vector.MINIMUM_RESOLUTION) {
-      if (Math.abs(topLat - Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION && Math.abs(bottomLat + Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION)
-        return new GeoWorld(planetModel);
-      if (Math.abs(topLat - bottomLat) < Vector.MINIMUM_RESOLUTION) {
-        if (Math.abs(topLat - Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION || Math.abs(topLat + Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION)
-          return new GeoDegeneratePoint(planetModel, topLat, 0.0);
-        return new GeoDegenerateLatitudeZone(planetModel, topLat);
-      }
-      if (Math.abs(topLat - Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION)
-        return new GeoNorthLatitudeZone(planetModel, bottomLat);
-      else if (Math.abs(bottomLat + Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION)
-        return new GeoSouthLatitudeZone(planetModel, topLat);
-      return new GeoLatitudeZone(planetModel, topLat, bottomLat);
-    }
-    //System.err.println(" not latitude zone");
-    double extent = rightLon - leftLon;
-    if (extent < 0.0)
-      extent += Math.PI * 2.0;
-    if (topLat == Math.PI * 0.5 && bottomLat == -Math.PI * 0.5) {
-      if (Math.abs(leftLon - rightLon) < Vector.MINIMUM_RESOLUTION)
-        return new GeoDegenerateLongitudeSlice(planetModel, leftLon);
-
-      if (extent >= Math.PI)
-        return new GeoWideLongitudeSlice(planetModel, leftLon, rightLon);
-
-      return new GeoLongitudeSlice(planetModel, leftLon, rightLon);
-    }
-    //System.err.println(" not longitude slice");
-    if (Math.abs(leftLon - rightLon) < Vector.MINIMUM_RESOLUTION) {
-      if (Math.abs(topLat - bottomLat) < Vector.MINIMUM_RESOLUTION)
-        return new GeoDegeneratePoint(planetModel, topLat, leftLon);
-      return new GeoDegenerateVerticalLine(planetModel, topLat, bottomLat, leftLon);
-    }
-    //System.err.println(" not vertical line");
-    if (extent >= Math.PI) {
-      if (Math.abs(topLat - bottomLat) < Vector.MINIMUM_RESOLUTION) {
-        //System.err.println(" wide degenerate line");
-        return new GeoWideDegenerateHorizontalLine(planetModel, topLat, leftLon, rightLon);
-      }
-      if (Math.abs(topLat - Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION) {
-        return new GeoWideNorthRectangle(planetModel, bottomLat, leftLon, rightLon);
-      } else if (Math.abs(bottomLat + Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION) {
-        return new GeoWideSouthRectangle(planetModel, topLat, leftLon, rightLon);
-      }
-      //System.err.println(" wide rect");
-      return new GeoWideRectangle(planetModel, topLat, bottomLat, leftLon, rightLon);
-    }
-    if (Math.abs(topLat - bottomLat) < Vector.MINIMUM_RESOLUTION) {
-      if (Math.abs(topLat - Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION || Math.abs(topLat + Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION) {
-        return new GeoDegeneratePoint(planetModel, topLat, 0.0);
-      }
-      //System.err.println(" horizontal line");
-      return new GeoDegenerateHorizontalLine(planetModel, topLat, leftLon, rightLon);
-    }
-    if (Math.abs(topLat - Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION) {
-      return new GeoNorthRectangle(planetModel, bottomLat, leftLon, rightLon);
-    } else if (Math.abs(bottomLat + Math.PI * 0.5) <  Vector.MINIMUM_RESOLUTION) {
-      return new GeoSouthRectangle(planetModel, topLat, leftLon, rightLon);
-    }
-    //System.err.println(" rectangle");
-    return new GeoRectangle(planetModel, topLat, bottomLat, leftLon, rightLon);
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseBBox.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseBBox.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseBBox.java
deleted file mode 100644
index f40a0a1..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseBBox.java
+++ /dev/null
@@ -1,72 +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.geo3d;
-
-/**
- * All bounding box shapes can derive from this base class, which furnishes
- * some common code
- *
- * @lucene.internal
- */
-public abstract class GeoBaseBBox extends GeoBaseMembershipShape implements GeoBBox {
-
-  /** Construct, given planet model.
-   *@param planetModel is the planet model.
-   */
-  public GeoBaseBBox(final PlanetModel planetModel) {
-    super(planetModel);
-  }
-
-  // Signals for relationship of edge points to shape
-  
-  /** All edgepoints inside shape */
-  protected final static int ALL_INSIDE = 0;
-  /** Some edgepoints inside shape */
-  protected final static int SOME_INSIDE = 1;
-  /** No edgepoints inside shape */
-  protected final static int NONE_INSIDE = 2;
-
-  /** Determine the relationship between this BBox and the provided
-   * shape's edgepoints.
-   *@param path is the shape.
-   *@return the relationship.
-   */
-  protected int isShapeInsideBBox(final GeoShape path) {
-    final GeoPoint[] pathPoints = path.getEdgePoints();
-    boolean foundOutside = false;
-    boolean foundInside = false;
-    for (GeoPoint p : pathPoints) {
-      if (isWithin(p)) {
-        foundInside = true;
-      } else {
-        foundOutside = true;
-      }
-      if (foundInside && foundOutside) {
-        return SOME_INSIDE;
-      }
-    }
-    if (!foundInside && !foundOutside)
-      return NONE_INSIDE;
-    if (foundInside && !foundOutside)
-      return ALL_INSIDE;
-    if (foundOutside && !foundInside)
-      return NONE_INSIDE;
-    return SOME_INSIDE;
-  }
-
-}
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseCircle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseCircle.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseCircle.java
deleted file mode 100644
index 8c306d7..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseCircle.java
+++ /dev/null
@@ -1,34 +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.geo3d;
-
-/**
- * GeoCircles have all the characteristics of GeoBaseDistanceShapes, plus GeoSizeable.
- *
- * @lucene.experimental
- */
-public abstract class GeoBaseCircle extends GeoBaseDistanceShape implements GeoCircle {
-
-  /** Constructor.
-   *@param planetModel is the planet model to use.
-   */
-  public GeoBaseCircle(final PlanetModel planetModel) {
-    super(planetModel);
-  }
-
-}
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseDistanceShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseDistanceShape.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseDistanceShape.java
deleted file mode 100644
index 1c8306a..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseDistanceShape.java
+++ /dev/null
@@ -1,56 +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.geo3d;
-
-/**
- * Distance shapes have capabilities of both geohashing and distance
- * computation (which also includes point membership determination).
- *
- * @lucene.experimental
- */
-public abstract class GeoBaseDistanceShape extends GeoBaseMembershipShape implements GeoDistanceShape {
-
-  /** Constructor.
-   *@param planetModel is the planet model to use.
-   */
-  public GeoBaseDistanceShape(final PlanetModel planetModel) {
-    super(planetModel);
-  }
-
-  @Override
-  public boolean isWithin(Vector point) {
-    return isWithin(point.x, point.y, point.z);
-  }
-
-  @Override
-  public double computeDistance(final DistanceStyle distanceStyle, final GeoPoint point) {
-    return computeDistance(distanceStyle, point.x, point.y, point.z);
-  }
-
-  @Override
-  public double computeDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    if (!isWithin(x,y,z)) {
-      return Double.MAX_VALUE;
-    }
-    return distance(distanceStyle, x, y, z);
-  }
-
-  /** Called by a {@code computeDistance} method if X/Y/Z is not within this shape. */
-  protected abstract double distance(final DistanceStyle distanceStyle, final double x, final double y, final double z);
-
-}
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseMembershipShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseMembershipShape.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseMembershipShape.java
deleted file mode 100644
index a6bba8f..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseMembershipShape.java
+++ /dev/null
@@ -1,56 +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.geo3d;
-
-/**
- * Membership shapes have capabilities of both geohashing and membership
- * determination.  This is a useful baseclass for them.
- *
- * @lucene.experimental
- */
-public abstract class GeoBaseMembershipShape extends GeoBaseShape implements GeoMembershipShape {
-
-  /** Constructor.
-   *@param planetModel is the planet model to use.
-   */
-  public GeoBaseMembershipShape(final PlanetModel planetModel) {
-    super(planetModel);
-  }
-
-  @Override
-  public boolean isWithin(Vector point) {
-    return isWithin(point.x, point.y, point.z);
-  }
-
-  @Override
-  public double computeOutsideDistance(final DistanceStyle distanceStyle, final GeoPoint point) {
-    return computeOutsideDistance(distanceStyle, point.x, point.y, point.z);
-  }
-
-  @Override
-  public double computeOutsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    if (isWithin(x,y,z)) {
-      return 0.0;
-    }
-    return outsideDistance(distanceStyle, x,y,z);
-  }
-
-  /** Called by a {@code computeOutsideDistance} method if X/Y/Z is not within this shape. */
-  protected abstract double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z);
-
-}
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBasePolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBasePolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBasePolygon.java
deleted file mode 100644
index 50ad0dc..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBasePolygon.java
+++ /dev/null
@@ -1,34 +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.geo3d;
-
-/**
- * GeoBasePolygon objects are the base class of most GeoPolygon objects.
- *
- * @lucene.experimental
- */
-public abstract class GeoBasePolygon extends GeoBaseMembershipShape implements GeoPolygon {
-
-  /** Constructor.
-   *@param planetModel is the planet model to use.
-   */
-  public GeoBasePolygon(final PlanetModel planetModel) {
-    super(planetModel);
-  }
-
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseShape.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseShape.java
deleted file mode 100644
index 146cfe8..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoBaseShape.java
+++ /dev/null
@@ -1,59 +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.geo3d;
-
-/**
- * Base extended shape object.
- *
- * @lucene.internal
- */
-public abstract class GeoBaseShape extends BasePlanetObject implements GeoShape {
-
-  /** Constructor.
-   *@param planetModel is the planet model to use.
-   */
-  public GeoBaseShape(final PlanetModel planetModel) {
-    super(planetModel);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    if (isWithin(planetModel.NORTH_POLE)) {
-      bounds.noTopLatitudeBound().noLongitudeBound()
-        .addPoint(planetModel.NORTH_POLE);
-    }
-    if (isWithin(planetModel.SOUTH_POLE)) {
-      bounds.noBottomLatitudeBound().noLongitudeBound()
-        .addPoint(planetModel.SOUTH_POLE);
-    }
-    if (isWithin(planetModel.MIN_X_POLE)) {
-      bounds.addPoint(planetModel.MIN_X_POLE);
-    }
-    if (isWithin(planetModel.MAX_X_POLE)) {
-      bounds.addPoint(planetModel.MAX_X_POLE);
-    }
-    if (isWithin(planetModel.MIN_Y_POLE)) {
-      bounds.addPoint(planetModel.MIN_Y_POLE);
-    }
-    if (isWithin(planetModel.MAX_Y_POLE)) {
-      bounds.addPoint(planetModel.MAX_Y_POLE);
-    }
-  }
-
-}
-
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCircle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCircle.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCircle.java
deleted file mode 100755
index 154cdc4..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCircle.java
+++ /dev/null
@@ -1,25 +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.geo3d;
-
-/**
- * Interface describing circular area with a center and radius.
- *
- * @lucene.experimental
- */
-public interface GeoCircle extends GeoDistanceShape, GeoSizeable {
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCircleFactory.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCircleFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCircleFactory.java
deleted file mode 100644
index 2bb8ffc..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCircleFactory.java
+++ /dev/null
@@ -1,43 +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.geo3d;
-
-/**
- * Class which constructs a GeoCircle representing an arbitrary circle.
- *
- * @lucene.experimental
- */
-public class GeoCircleFactory {
-  private GeoCircleFactory() {
-  }
-
-  /**
-   * Create a GeoCircle of the right kind given the specified bounds.
-   * @param planetModel is the planet model.
-   * @param latitude is the center latitude.
-   * @param longitude is the center longitude.
-   * @param radius is the radius angle.
-   * @return a GeoCircle corresponding to what was specified.
-   */
-  public static GeoCircle makeGeoCircle(final PlanetModel planetModel, final double latitude, final double longitude, final double radius) {
-    if (radius < Vector.MINIMUM_RESOLUTION) {
-      return new GeoDegeneratePoint(planetModel, latitude, longitude);
-    }
-    return new GeoStandardCircle(planetModel, latitude, longitude, radius);
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCompositeMembershipShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCompositeMembershipShape.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCompositeMembershipShape.java
deleted file mode 100755
index 25bdda0..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCompositeMembershipShape.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.geo3d;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * GeoComposite is a set of GeoMembershipShape's, treated as a unit.
- *
- * @lucene.experimental
- */
-public class GeoCompositeMembershipShape implements GeoMembershipShape {
-  /** The list of shapes. */
-  protected final List<GeoMembershipShape> shapes = new ArrayList<GeoMembershipShape>();
-
-  /** Constructor.
-   */
-  public GeoCompositeMembershipShape() {
-  }
-
-  /**
-   * Add a shape to the composite.
-   *@param shape is the shape to add.
-   */
-  public void addShape(final GeoMembershipShape shape) {
-    shapes.add(shape);
-  }
-
-  @Override
-  public boolean isWithin(final Vector point) {
-    return isWithin(point.x, point.y, point.z);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    for (GeoMembershipShape shape : shapes) {
-      if (shape.isWithin(x, y, z))
-        return true;
-    }
-    return false;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return shapes.get(0).getEdgePoints();
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    for (GeoMembershipShape shape : shapes) {
-      if (shape.intersects(p, notablePoints, bounds))
-        return true;
-    }
-    return false;
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    for (GeoMembershipShape shape : shapes) {
-      shape.getBounds(bounds);
-    }
-  }
-
-  @Override
-  public double computeOutsideDistance(final DistanceStyle distanceStyle, final GeoPoint point) {
-    return computeOutsideDistance(distanceStyle, point.x, point.y, point.z);
-  }
-
-  @Override
-  public double computeOutsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    if (isWithin(x,y,z))
-      return 0.0;
-    double distance = Double.MAX_VALUE;
-    for (GeoMembershipShape shape : shapes) {
-      final double normalDistance = shape.computeOutsideDistance(distanceStyle, x, y, z);
-      if (normalDistance < distance) {
-        distance = normalDistance;
-      }
-    }
-    return distance;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoCompositeMembershipShape))
-      return false;
-    GeoCompositeMembershipShape other = (GeoCompositeMembershipShape) o;
-
-    return super.equals(o) && shapes.equals(other.shapes);
-  }
-
-  @Override
-  public int hashCode() {
-    return super.hashCode() * 31 + shapes.hashCode();//TODO cache
-  }
-
-  @Override
-  public String toString() {
-    return "GeoCompositeMembershipShape: {" + shapes + '}';
-  }
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCompositePolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCompositePolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCompositePolygon.java
deleted file mode 100644
index b537590..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoCompositePolygon.java
+++ /dev/null
@@ -1,31 +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.geo3d;
-
-/**
- * GeoCompositePolygon is a specific implementation of GeoMembershipShape, which implements GeoPolygon explicitly.
- *
- * @lucene.experimental
- */
-public class GeoCompositePolygon extends GeoCompositeMembershipShape implements GeoPolygon {
-  /** Constructor.
-   */
-  public GeoCompositePolygon() {
-  }
-
-}
-  


[22/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 3a31a8c)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideSouthRectangle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideSouthRectangle.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideSouthRectangle.java
new file mode 100644
index 0000000..da9799a
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideSouthRectangle.java
@@ -0,0 +1,284 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Bounding box wider than PI but limited on three sides (top lat,
+ * left lon, right lon).
+ *
+ * @lucene.internal
+ */
+public class GeoWideSouthRectangle extends GeoBaseBBox {
+  /** Top latitude of rect */
+  protected final double topLat;
+  /** Left longitude of rect */
+  protected final double leftLon;
+  /** Right longitude of rect */
+  protected final double rightLon;
+
+  /** Cosine of middle latitude */
+  protected final double cosMiddleLat;
+
+  /** Upper left hand corner */
+  protected final GeoPoint ULHC;
+  /** Upper right hand corner */
+  protected final GeoPoint URHC;
+
+  /** The top plane */
+  protected final SidedPlane topPlane;
+  /** The left plane */
+  protected final SidedPlane leftPlane;
+  /** The right plane */
+  protected final SidedPlane rightPlane;
+
+  /** Notable points for top plane */
+  protected final GeoPoint[] topPlanePoints;
+  /** Notable points for left plane */
+  protected final GeoPoint[] leftPlanePoints;
+  /** Notable points for right plane */
+  protected final GeoPoint[] rightPlanePoints;
+
+  /** Center point */
+  protected final GeoPoint centerPoint;
+
+  /** Left/right bounds */
+  protected final EitherBound eitherBound;
+
+  /** A point on the edge */
+  protected final GeoPoint[] edgePoints;
+
+  /**
+   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}.
+   * Horizontal angle must be greater than or equal to PI.
+   */
+  public GeoWideSouthRectangle(final PlanetModel planetModel, final double topLat, final double leftLon, double rightLon) {
+    super(planetModel);
+    // Argument checking
+    if (topLat > Math.PI * 0.5 || topLat < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Top latitude out of range");
+    if (leftLon < -Math.PI || leftLon > Math.PI)
+      throw new IllegalArgumentException("Left longitude out of range");
+    if (rightLon < -Math.PI || rightLon > Math.PI)
+      throw new IllegalArgumentException("Right longitude out of range");
+    double extent = rightLon - leftLon;
+    if (extent < 0.0) {
+      extent += 2.0 * Math.PI;
+    }
+    if (extent < Math.PI)
+      throw new IllegalArgumentException("Width of rectangle too small");
+
+    this.topLat = topLat;
+    this.leftLon = leftLon;
+    this.rightLon = rightLon;
+
+    final double sinTopLat = Math.sin(topLat);
+    final double cosTopLat = Math.cos(topLat);
+    final double sinLeftLon = Math.sin(leftLon);
+    final double cosLeftLon = Math.cos(leftLon);
+    final double sinRightLon = Math.sin(rightLon);
+    final double cosRightLon = Math.cos(rightLon);
+
+    // Now build the four points
+    this.ULHC = new GeoPoint(planetModel, sinTopLat, sinLeftLon, cosTopLat, cosLeftLon, topLat, leftLon);
+    this.URHC = new GeoPoint(planetModel, sinTopLat, sinRightLon, cosTopLat, cosRightLon, topLat, rightLon);
+
+    final double middleLat = (topLat - Math.PI * 0.5) * 0.5;
+    final double sinMiddleLat = Math.sin(middleLat);
+    this.cosMiddleLat = Math.cos(middleLat);
+    // Normalize
+    while (leftLon > rightLon) {
+      rightLon += Math.PI * 2.0;
+    }
+    final double middleLon = (leftLon + rightLon) * 0.5;
+    final double sinMiddleLon = Math.sin(middleLon);
+    final double cosMiddleLon = Math.cos(middleLon);
+
+    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinMiddleLon, cosMiddleLat, cosMiddleLon);
+
+    this.topPlane = new SidedPlane(centerPoint, planetModel, sinTopLat);
+    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
+    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
+
+    this.topPlanePoints = new GeoPoint[]{ULHC, URHC};
+    this.leftPlanePoints = new GeoPoint[]{ULHC, planetModel.SOUTH_POLE};
+    this.rightPlanePoints = new GeoPoint[]{URHC, planetModel.SOUTH_POLE};
+
+    this.eitherBound = new EitherBound();
+    
+    this.edgePoints = new GeoPoint[]{planetModel.SOUTH_POLE};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    final double newTopLat = topLat + angle;
+    final double newBottomLat = -Math.PI * 0.5;
+    // Figuring out when we escalate to a special case requires some prefiguring
+    double currentLonSpan = rightLon - leftLon;
+    if (currentLonSpan < 0.0)
+      currentLonSpan += Math.PI * 2.0;
+    double newLeftLon = leftLon - angle;
+    double newRightLon = rightLon + angle;
+    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
+      newLeftLon = -Math.PI;
+      newRightLon = Math.PI;
+    }
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return topPlane.isWithin(x, y, z) &&
+        (leftPlane.isWithin(x, y, z) ||
+            rightPlane.isWithin(x, y, z));
+  }
+
+  @Override
+  public double getRadius() {
+    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
+    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
+    // the distance to the right or left edge from the center.
+    final double centerAngle = (rightLon - (rightLon + leftLon) * 0.5) * cosMiddleLat;
+    final double topAngle = centerPoint.arcDistance(URHC);
+    return Math.max(centerAngle, topAngle);
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    return centerPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    // Right and left bounds are essentially independent hemispheres; crossing into the wrong part of one
+    // requires crossing into the right part of the other.  So intersection can ignore the left/right bounds.
+    return p.intersects(planetModel, topPlane, notablePoints, topPlanePoints, bounds, eitherBound) ||
+        p.intersects(planetModel, leftPlane, notablePoints, leftPlanePoints, bounds, topPlane) ||
+        p.intersects(planetModel, rightPlane, notablePoints, rightPlanePoints, bounds, topPlane);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds.isWide()
+      .addHorizontalPlane(planetModel, topLat, topPlane, eitherBound)
+      .addVerticalPlane(planetModel, rightLon, rightPlane, topPlane)
+      .addVerticalPlane(planetModel, leftLon, leftPlane, topPlane)
+      .addPoint(ULHC).addPoint(URHC).addPoint(planetModel.SOUTH_POLE);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    //System.err.println(this+" comparing to "+path);
+    final int insideRectangle = isShapeInsideBBox(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some inside");
+      return OVERLAPS;
+    }
+
+    final boolean insideShape = path.isWithin(planetModel.SOUTH_POLE);
+
+    if (insideRectangle == ALL_INSIDE && insideShape) {
+      //System.err.println(" both inside each other");
+      return OVERLAPS;
+    }
+
+    if (path.intersects(topPlane, topPlanePoints, eitherBound) ||
+        path.intersects(leftPlane, leftPlanePoints, topPlane) ||
+        path.intersects(rightPlane, rightPlanePoints, topPlane)) {
+      //System.err.println(" edges intersect");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      //System.err.println(" shape inside rectangle");
+      return WITHIN;
+    }
+
+    if (insideShape) {
+      //System.err.println(" rectangle inside shape");
+      return CONTAINS;
+    }
+
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    final double topDistance = distanceStyle.computeDistance(planetModel, topPlane, x,y,z, eitherBound);
+    // Because the rectangle exceeds 180 degrees, it is safe to compute the horizontally 
+    // unbounded distance to both the left and the right and only take the minimum of the two.
+    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, topPlane);
+    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, topPlane);
+    
+    final double ULHCDistance = distanceStyle.computeDistance(ULHC, x,y,z);
+    final double URHCDistance = distanceStyle.computeDistance(URHC, x,y,z);
+    
+    return Math.min(
+      Math.min(
+        topDistance,
+        Math.min(leftDistance, rightDistance)),
+      Math.min(ULHCDistance, URHCDistance));
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoWideSouthRectangle))
+      return false;
+    GeoWideSouthRectangle other = (GeoWideSouthRectangle) o;
+    return super.equals(o) && other.ULHC.equals(ULHC) && other.URHC.equals(URHC);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + ULHC.hashCode();
+    result = 31 * result + URHC.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoWideSouthRectangle: {planetmodel="+planetModel+", toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
+  }
+
+  /** Membership implementation representing width more than 180.
+   */
+  protected class EitherBound implements Membership {
+    /** Constructor.
+     */
+    public EitherBound() {
+    }
+
+    @Override
+    public boolean isWithin(final Vector v) {
+      return leftPlane.isWithin(v) || rightPlane.isWithin(v);
+    }
+
+    @Override
+    public boolean isWithin(final double x, final double y, final double z) {
+      return leftPlane.isWithin(x, y, z) || rightPlane.isWithin(x, y, z);
+    }
+  }
+}
+  
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWorld.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWorld.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWorld.java
new file mode 100755
index 0000000..25bdc96
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWorld.java
@@ -0,0 +1,106 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Bounding box including the entire world.
+ *
+ * @lucene.internal
+ */
+public class GeoWorld extends GeoBaseBBox {
+  /** No points on the edge of the shape */
+  protected final static GeoPoint[] edgePoints = new GeoPoint[0];
+  /** Point in the middle of the world */
+  protected final GeoPoint originPoint;
+  
+  /** Constructor.
+   *@param planetModel is the planet model.
+   */
+  public GeoWorld(final PlanetModel planetModel) {
+    super(planetModel);
+    originPoint = new GeoPoint(planetModel.ab, 1.0, 0.0, 0.0);
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    return this;
+  }
+
+  @Override
+  public double getRadius() {
+    return Math.PI;
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    // Totally arbitrary
+    return originPoint;
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return true;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return false;
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    // Unnecessary
+    //bounds.noLongitudeBound().noTopLatitudeBound().noBottomLatitudeBound();
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    if (path.getEdgePoints().length > 0)
+      // Path is always within the world
+      return WITHIN;
+
+    return OVERLAPS;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    return 0.0;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoWorld))
+      return false;
+    return super.equals(o);
+  }
+
+  @Override
+  public int hashCode() {
+    return super.hashCode();
+  }
+
+  @Override
+  public String toString() {
+    return "GeoWorld: {planetmodel="+planetModel+"}";
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/LatLonBounds.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/LatLonBounds.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/LatLonBounds.java
new file mode 100644
index 0000000..627fdae
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/LatLonBounds.java
@@ -0,0 +1,322 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * An object for accumulating latitude/longitude bounds information.
+ *
+ * @lucene.experimental
+ */
+public class LatLonBounds implements Bounds {
+
+  /** Set to true if no longitude bounds can be stated */
+  protected boolean noLongitudeBound = false;
+  /** Set to true if no top latitude bound can be stated */
+  protected boolean noTopLatitudeBound = false;
+  /** Set to true if no bottom latitude bound can be stated */
+  protected boolean noBottomLatitudeBound = false;
+
+  /** If non-null, the minimum latitude bound */
+  protected Double minLatitude = null;
+  /** If non-null, the maximum latitude bound */
+  protected Double maxLatitude = null;
+
+  // For longitude bounds, this class needs to worry about keeping track of the distinction
+  // between left-side bounds and right-side bounds.  Points are always submitted in pairs
+  // which have a maximum longitude separation of Math.PI.  It's therefore always possible
+  // to determine which point represents a left bound, and which point represents a right
+  // bound.
+  //
+  // The next problem is how to compare two of the same kind of bound, e.g. two left bounds.
+  // We need to keep track of the leftmost longitude of the shape, but since this is a circle,
+  // this is arbitrary.  What we could try to do instead would be to find a pair of (left,right) bounds such
+  // that:
+  // (1) all other bounds are within, and
+  // (2) the left minus right distance is minimized
+  // Unfortunately, there are still shapes that cannot be summarized in this way correctly.
+  // For example. consider a spiral that entirely circles the globe; we might arbitrarily choose
+  // lat/lon bounds that do not in fact circle the globe.
+  //
+  // One way to handle the longitude issue correctly is therefore to stipulate that we
+  // walk the bounds of the shape in some kind of connected order.  Each point or circle is therefore
+  // added in a sequence.  We also need an interior point to make sure we have the right
+  // choice of longitude bounds.  But even with this, we still can't always choose whether the actual shape
+  // goes right or left.
+  //
+  // We can make the specification truly general by submitting the following in order:
+  // addSide(PlaneSide side, Membership... constraints)
+  // ...
+  // This is unambiguous, but I still can't see yet how this would help compute the bounds.  The plane
+  // solution would in general seem to boil down to the same logic that relies on points along the path
+  // to define the shape boundaries.  I guess the one thing that you do know for a bounded edge is that
+  // the endpoints are actually connected.  But it is not clear whether relationship helps in any way.
+  //
+  // In any case, if we specify shapes by a sequence of planes, we should stipulate that multiple sequences
+  // are allowed, provided they progressively tile an area of the sphere that is connected and sequential.
+  // For example, paths do alternating rectangles and circles, in sequence.  Each sequence member is
+  // described by a sequence of planes.  I think it would also be reasonable to insist that the first segment
+  // of a shape overlap or adjoin the previous shape.
+  //
+  // Here's a way to think about it that might help: Traversing every edge should grow the longitude bounds
+  // in the direction of the traversal.  So if the traversal is always known to be less than PI in total longitude
+  // angle, then it is possible to use the endpoints to determine the unambiguous extension of the envelope.
+  // For example, say you are currently at longitude -0.5.  The next point is at longitude PI-0.1.  You could say
+  // that the difference in longitude going one way around would be beter than the distance the other way
+  // around, and therefore the longitude envelope should be extended accordingly.  But in practice, when an
+  // edge goes near a pole and may be inclined as well, the longer longitude change might be the right path, even
+  // if the arc length is short.  So this too doesn't work.
+  //
+  // Given we have a hard time making an exact match, here's the current proposal.  The proposal is a
+  // heuristic, based on the idea that most areas are small compared to the circumference of the globe.
+  // We keep track of the last point we saw, and take each point as it arrives, and compute its longitude.
+  // Then, we have a choice as to which way to expand the envelope: we can expand by going to the left or
+  // to the right.  We choose the direction with the least longitude difference.  (If we aren't sure,
+  // and can recognize that, we can set "unconstrained in longitude".)
+
+  /** If non-null, the left longitude bound */
+  protected Double leftLongitude = null;
+  /** If non-null, the right longitude bound */
+  protected Double rightLongitude = null;
+
+  /** Construct an empty bounds object */
+  public LatLonBounds() {
+  }
+
+  // Accessor methods
+  
+  /** Get maximum latitude, if any.
+   *@return maximum latitude or null.
+   */
+  public Double getMaxLatitude() {
+    return maxLatitude;
+  }
+
+  /** Get minimum latitude, if any.
+   *@return minimum latitude or null.
+   */
+  public Double getMinLatitude() {
+    return minLatitude;
+  }
+
+  /** Get left longitude, if any.
+   *@return left longitude, or null.
+   */
+  public Double getLeftLongitude() {
+    return leftLongitude;
+  }
+
+  /** Get right longitude, if any.
+   *@return right longitude, or null.
+   */
+  public Double getRightLongitude() {
+    return rightLongitude;
+  }
+
+  // Degenerate case check
+  
+  /** Check if there's no longitude bound.
+   *@return true if no longitude bound.
+   */
+  public boolean checkNoLongitudeBound() {
+    return noLongitudeBound;
+  }
+
+  /** Check if there's no top latitude bound.
+   *@return true if no top latitude bound.
+   */
+  public boolean checkNoTopLatitudeBound() {
+    return noTopLatitudeBound;
+  }
+
+  /** Check if there's no bottom latitude bound.
+   *@return true if no bottom latitude bound.
+   */
+  public boolean checkNoBottomLatitudeBound() {
+    return noBottomLatitudeBound;
+  }
+
+  // Modification methods
+  
+  @Override
+  public Bounds addPlane(final PlanetModel planetModel, final Plane plane, final Membership... bounds) {
+    plane.recordBounds(planetModel, this, bounds);
+    return this;
+  }
+
+  @Override
+  public Bounds addHorizontalPlane(final PlanetModel planetModel,
+    final double latitude,
+    final Plane horizontalPlane,
+    final Membership... bounds) {
+    if (!noTopLatitudeBound || !noBottomLatitudeBound) {
+      addLatitudeBound(latitude);
+    }
+    return this;
+  }
+    
+  @Override
+  public Bounds addVerticalPlane(final PlanetModel planetModel,
+    final double longitude,
+    final Plane verticalPlane,
+    final Membership... bounds) {
+    if (!noLongitudeBound) {
+      addLongitudeBound(longitude);
+    }
+    return this;
+  }
+
+  @Override
+  public Bounds isWide() {
+    return noLongitudeBound();
+  }
+
+  @Override
+  public Bounds addXValue(final GeoPoint point) {
+    if (!noLongitudeBound) {
+      // Get a longitude value
+      addLongitudeBound(point.getLongitude());
+    }
+    return this;
+  }
+
+  @Override
+  public Bounds addYValue(final GeoPoint point) {
+    if (!noLongitudeBound) {
+      // Get a longitude value
+      addLongitudeBound(point.getLongitude());
+    }
+    return this;
+  }
+
+  @Override
+  public Bounds addZValue(final GeoPoint point) {
+    if (!noTopLatitudeBound || !noBottomLatitudeBound) {
+      // Compute a latitude value
+      double latitude = point.getLatitude();
+      addLatitudeBound(latitude);
+    }
+    return this;
+  }
+
+  @Override
+  public Bounds addPoint(GeoPoint point) {
+    if (!noLongitudeBound) {
+      // Get a longitude value
+      addLongitudeBound(point.getLongitude());
+    }
+    if (!noTopLatitudeBound || !noBottomLatitudeBound) {
+      // Compute a latitude value
+      addLatitudeBound(point.getLatitude());
+    }
+    return this;
+  }
+  
+  @Override
+  public Bounds noLongitudeBound() {
+    noLongitudeBound = true;
+    leftLongitude = null;
+    rightLongitude = null;
+    return this;
+  }
+
+  @Override
+  public Bounds noTopLatitudeBound() {
+    noTopLatitudeBound = true;
+    maxLatitude = null;
+    return this;
+  }
+
+  @Override
+  public Bounds noBottomLatitudeBound() {
+    noBottomLatitudeBound = true;
+    minLatitude = null;
+    return this;
+  }
+
+  // Protected methods
+  
+  /** Update latitude bound.
+   *@param latitude is the latitude.
+   */
+  protected void addLatitudeBound(double latitude) {
+    if (!noTopLatitudeBound && (maxLatitude == null || latitude > maxLatitude))
+      maxLatitude = latitude;
+    if (!noBottomLatitudeBound && (minLatitude == null || latitude < minLatitude))
+      minLatitude = latitude;
+  }
+
+  /** Update longitude bound.
+   *@param longitude is the new longitude value.
+   */
+  protected void addLongitudeBound(double longitude) {
+    // If this point is within the current bounds, we're done; otherwise
+    // expand one side or the other.
+    if (leftLongitude == null && rightLongitude == null) {
+      leftLongitude = longitude;
+      rightLongitude = longitude;
+    } else {
+      // Compute whether we're to the right of the left value.  But the left value may be greater than
+      // the right value.
+      double currentLeftLongitude = leftLongitude;
+      double currentRightLongitude = rightLongitude;
+      if (currentRightLongitude < currentLeftLongitude)
+        currentRightLongitude += 2.0 * Math.PI;
+      // We have a range to look at that's going in the right way.
+      // Now, do the same trick with the computed longitude.
+      if (longitude < currentLeftLongitude)
+        longitude += 2.0 * Math.PI;
+
+      if (longitude < currentLeftLongitude || longitude > currentRightLongitude) {
+        // Outside of current bounds.  Consider carefully how we'll expand.
+        double leftExtensionAmt;
+        double rightExtensionAmt;
+        if (longitude < currentLeftLongitude) {
+          leftExtensionAmt = currentLeftLongitude - longitude;
+        } else {
+          leftExtensionAmt = currentLeftLongitude + 2.0 * Math.PI - longitude;
+        }
+        if (longitude > currentRightLongitude) {
+          rightExtensionAmt = longitude - currentRightLongitude;
+        } else {
+          rightExtensionAmt = longitude + 2.0 * Math.PI - currentRightLongitude;
+        }
+        if (leftExtensionAmt < rightExtensionAmt) {
+          currentLeftLongitude = leftLongitude - leftExtensionAmt;
+          while (currentLeftLongitude <= -Math.PI) {
+            currentLeftLongitude += 2.0 * Math.PI;
+          }
+          leftLongitude = currentLeftLongitude;
+        } else {
+          currentRightLongitude = rightLongitude + rightExtensionAmt;
+          while (currentRightLongitude > Math.PI) {
+            currentRightLongitude -= 2.0 * Math.PI;
+          }
+          rightLongitude = currentRightLongitude;
+        }
+      }
+    }
+    double testRightLongitude = rightLongitude;
+    if (testRightLongitude < leftLongitude)
+      testRightLongitude += Math.PI * 2.0;
+    if (testRightLongitude - leftLongitude >= Math.PI) {
+      noLongitudeBound = true;
+      leftLongitude = null;
+      rightLongitude = null;
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/LinearDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/LinearDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/LinearDistance.java
new file mode 100644
index 0000000..0c89a16
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/LinearDistance.java
@@ -0,0 +1,56 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Linear distance computation style.
+ *
+ * @lucene.experimental
+ */
+public class LinearDistance implements DistanceStyle {
+  
+  /** A convenient instance */
+  public final static LinearDistance INSTANCE = new LinearDistance();
+  
+  /** Constructor.
+   */
+  public LinearDistance() {
+  }
+  
+  @Override
+  public double computeDistance(final GeoPoint point1, final GeoPoint point2) {
+    return point1.linearDistance(point2);
+  }
+  
+  @Override
+  public double computeDistance(final GeoPoint point1, final double x2, final double y2, final double z2) {
+    return point1.linearDistance(x2,y2,z2);
+  }
+
+  @Override
+  public double computeDistance(final PlanetModel planetModel, final Plane plane, final GeoPoint point, final Membership... bounds) {
+    return plane.linearDistance(planetModel, point, bounds);
+  }
+  
+  @Override
+  public double computeDistance(final PlanetModel planetModel, final Plane plane, final double x, final double y, final double z, final Membership... bounds) {
+    return plane.linearDistance(planetModel, x,y,z, bounds);
+  }
+
+}
+
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/LinearSquaredDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/LinearSquaredDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/LinearSquaredDistance.java
new file mode 100644
index 0000000..3fc37da
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/LinearSquaredDistance.java
@@ -0,0 +1,56 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Linear squared distance computation style.
+ *
+ * @lucene.experimental
+ */
+public class LinearSquaredDistance implements DistanceStyle {
+  
+  /** A convenient instance */
+  public final static LinearSquaredDistance INSTANCE = new LinearSquaredDistance();
+  
+  /** Constructor.
+   */
+  public LinearSquaredDistance() {
+  }
+  
+  @Override
+  public double computeDistance(final GeoPoint point1, final GeoPoint point2) {
+    return point1.linearDistanceSquared(point2);
+  }
+  
+  @Override
+  public double computeDistance(final GeoPoint point1, final double x2, final double y2, final double z2) {
+    return point1.linearDistanceSquared(x2,y2,z2);
+  }
+
+  @Override
+  public double computeDistance(final PlanetModel planetModel, final Plane plane, final GeoPoint point, final Membership... bounds) {
+    return plane.linearDistanceSquared(planetModel, point, bounds);
+  }
+  
+  @Override
+  public double computeDistance(final PlanetModel planetModel, final Plane plane, final double x, final double y, final double z, final Membership... bounds) {
+    return plane.linearDistanceSquared(planetModel, x,y,z, bounds);
+  }
+
+}
+
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Membership.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Membership.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Membership.java
new file mode 100755
index 0000000..0cf6ff0
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Membership.java
@@ -0,0 +1,46 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Implemented by Geo3D shapes that can calculate if a point is within it or not.
+ *
+ * @lucene.experimental
+ */
+public interface Membership {
+
+  /**
+   * Check if a point is within this shape.
+   *
+   * @param point is the point to check.
+   * @return true if the point is within this shape
+   */
+  public default boolean isWithin(final Vector point) {
+    return isWithin(point.x, point.y, point.z);
+  }
+
+  /**
+   * Check if a point is within this shape.
+   *
+   * @param x is x coordinate of point to check.
+   * @param y is y coordinate of point to check.
+   * @param z is z coordinate of point to check.
+   * @return true if the point is within this shape
+   */
+  public boolean isWithin(final double x, final double y, final double z);
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/NormalDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/NormalDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/NormalDistance.java
new file mode 100644
index 0000000..50b2c7f
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/NormalDistance.java
@@ -0,0 +1,56 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Normal distance computation style.
+ *
+ * @lucene.experimental
+ */
+public class NormalDistance implements DistanceStyle {
+  
+  /** A convenient instance */
+  public final static NormalDistance INSTANCE = new NormalDistance();
+  
+  /** Constructor.
+   */
+  public NormalDistance() {
+  }
+  
+  @Override
+  public double computeDistance(final GeoPoint point1, final GeoPoint point2) {
+    return point1.normalDistance(point2);
+  }
+  
+  @Override
+  public double computeDistance(final GeoPoint point1, final double x2, final double y2, final double z2) {
+    return point1.normalDistance(x2,y2,z2);
+  }
+
+  @Override
+  public double computeDistance(final PlanetModel planetModel, final Plane plane, final GeoPoint point, final Membership... bounds) {
+    return plane.normalDistance(point, bounds);
+  }
+  
+  @Override
+  public double computeDistance(final PlanetModel planetModel, final Plane plane, final double x, final double y, final double z, final Membership... bounds) {
+    return plane.normalDistance(x,y,z, bounds);
+  }
+
+}
+
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/NormalSquaredDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/NormalSquaredDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/NormalSquaredDistance.java
new file mode 100644
index 0000000..a355d09
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/NormalSquaredDistance.java
@@ -0,0 +1,56 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Normal squared distance computation style.
+ *
+ * @lucene.experimental
+ */
+public class NormalSquaredDistance implements DistanceStyle {
+  
+  /** A convenient instance */
+  public final static NormalSquaredDistance INSTANCE = new NormalSquaredDistance();
+  
+  /** Constructor.
+   */
+  public NormalSquaredDistance() {
+  }
+  
+  @Override
+  public double computeDistance(final GeoPoint point1, final GeoPoint point2) {
+    return point1.normalDistanceSquared(point2);
+  }
+  
+  @Override
+  public double computeDistance(final GeoPoint point1, final double x2, final double y2, final double z2) {
+    return point1.normalDistanceSquared(x2,y2,z2);
+  }
+
+  @Override
+  public double computeDistance(final PlanetModel planetModel, final Plane plane, final GeoPoint point, final Membership... bounds) {
+    return plane.normalDistanceSquared(point, bounds);
+  }
+  
+  @Override
+  public double computeDistance(final PlanetModel planetModel, final Plane plane, final double x, final double y, final double z, final Membership... bounds) {
+    return plane.normalDistanceSquared(x,y,z, bounds);
+  }
+
+}
+
+


[18/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 3a31a8c)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/test/org/apache/lucene/geo3d/PlaneTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/PlaneTest.java b/lucene/spatial3d/src/test/org/apache/lucene/geo3d/PlaneTest.java
deleted file mode 100644
index 2ac3856..0000000
--- a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/PlaneTest.java
+++ /dev/null
@@ -1,64 +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.geo3d;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-/**
- * Test basic plane functionality.
- */
-public class PlaneTest {
-
-
-  @Test
-  public void testIdenticalPlanes() {
-    final GeoPoint p = new GeoPoint(PlanetModel.SPHERE, 0.123, -0.456);
-    final Plane plane1 = new Plane(p, 0.0);
-    final Plane plane2 = new Plane(p, 0.0);
-    assertTrue(plane1.isNumericallyIdentical(plane2));
-    final Plane plane3 = new Plane(p, 0.1);
-    assertFalse(plane1.isNumericallyIdentical(plane3));
-    final Vector v1 = new Vector(0.1, -0.732, 0.9);
-    final double constant = 0.432;
-    final Vector v2 = new Vector(v1.x * constant, v1.y * constant, v1.z * constant);
-    final Plane p1 = new Plane(v1, 0.2);
-    final Plane p2 = new Plane(v2, 0.2 * constant);
-    assertTrue(p1.isNumericallyIdentical(p2));
-  }
-
-  @Test
-  public void testInterpolation() {
-    // [X=0.35168818443386646, Y=-0.19637966197066342, Z=0.9152870857244183],
-    // [X=0.5003343189532654, Y=0.522128543226148, Z=0.6906861469771293],
-
-    final GeoPoint start = new GeoPoint(0.35168818443386646, -0.19637966197066342, 0.9152870857244183);
-    final GeoPoint end = new GeoPoint(0.5003343189532654, 0.522128543226148, 0.6906861469771293);
-
-    // [A=-0.6135342247741855, B=0.21504338363863665, C=0.28188192383666794, D=0.0, side=-1.0] internal? false;
-    final Plane p = new Plane(-0.6135342247741855, 0.21504338363863665, 0.28188192383666794, 0.0);
-
-    final GeoPoint[] points = p.interpolate(start, end, new double[]{0.25, 0.50, 0.75});
-
-    for (GeoPoint point : points) {
-      assertTrue(p.evaluateIsZero(point));
-    }
-  }
-}
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/test/org/apache/lucene/geo3d/TestGeo3DPoint.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/TestGeo3DPoint.java b/lucene/spatial3d/src/test/org/apache/lucene/geo3d/TestGeo3DPoint.java
deleted file mode 100644
index 17a4075..0000000
--- a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/TestGeo3DPoint.java
+++ /dev/null
@@ -1,801 +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.geo3d;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.apache.lucene.codecs.Codec;
-import org.apache.lucene.codecs.FilterCodec;
-import org.apache.lucene.codecs.PointsFormat;
-import org.apache.lucene.codecs.PointsReader;
-import org.apache.lucene.codecs.PointsWriter;
-import org.apache.lucene.codecs.lucene60.Lucene60PointsReader;
-import org.apache.lucene.codecs.lucene60.Lucene60PointsWriter;
-import org.apache.lucene.document.Document;
-import org.apache.lucene.document.Field;
-import org.apache.lucene.document.NumericDocValuesField;
-import org.apache.lucene.index.DirectoryReader;
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.IndexWriter;
-import org.apache.lucene.index.IndexWriterConfig;
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.index.MultiDocValues;
-import org.apache.lucene.index.NumericDocValues;
-import org.apache.lucene.index.SegmentReadState;
-import org.apache.lucene.index.SegmentWriteState;
-import org.apache.lucene.index.Term;
-import org.apache.lucene.search.IndexSearcher;
-import org.apache.lucene.search.Query;
-import org.apache.lucene.search.SimpleCollector;
-import org.apache.lucene.store.Directory;
-import org.apache.lucene.store.MockDirectoryWrapper;
-import org.apache.lucene.util.FixedBitSet;
-import org.apache.lucene.util.IOUtils;
-import org.apache.lucene.util.LuceneTestCase;
-import org.apache.lucene.util.TestUtil;
-import org.junit.BeforeClass;
-
-import com.carrotsearch.randomizedtesting.generators.RandomInts;
-
-public class TestGeo3DPoint extends LuceneTestCase {
-
-  private static boolean smallBBox;
-  
-  @BeforeClass
-  public static void beforeClass() {
-    smallBBox = random().nextBoolean();
-    if (VERBOSE) {
-      System.err.println("TEST: smallBBox=" + smallBBox);
-    }
-  }
-
-  private static Codec getCodec() {
-    if (Codec.getDefault().getName().equals("Lucene60")) {
-      int maxPointsInLeafNode = TestUtil.nextInt(random(), 16, 2048);
-      double maxMBSortInHeap = 3.0 + (3*random().nextDouble());
-      if (VERBOSE) {
-        System.out.println("TEST: using Lucene60PointsFormat with maxPointsInLeafNode=" + maxPointsInLeafNode + " and maxMBSortInHeap=" + maxMBSortInHeap);
-      }
-
-      return new FilterCodec("Lucene60", Codec.getDefault()) {
-        @Override
-        public PointsFormat pointsFormat() {
-          return new PointsFormat() {
-            @Override
-            public PointsWriter fieldsWriter(SegmentWriteState writeState) throws IOException {
-              return new Lucene60PointsWriter(writeState, maxPointsInLeafNode, maxMBSortInHeap);
-            }
-
-            @Override
-            public PointsReader fieldsReader(SegmentReadState readState) throws IOException {
-              return new Lucene60PointsReader(readState);
-            }
-          };
-        }
-      };
-    } else {
-      return Codec.getDefault();
-    }
-  }
-
-  public void testBasic() throws Exception {
-    Directory dir = getDirectory();
-    IndexWriterConfig iwc = newIndexWriterConfig();
-    iwc.setCodec(getCodec());
-    IndexWriter w = new IndexWriter(dir, iwc);
-    Document doc = new Document();
-    doc.add(new Geo3DPoint("field", toRadians(50.7345267), toRadians(-97.5303555)));
-    w.addDocument(doc);
-    IndexReader r = DirectoryReader.open(w);
-    // We can't wrap with "exotic" readers because the query must see the BKD3DDVFormat:
-    IndexSearcher s = newSearcher(r, false);
-    assertEquals(1, s.search(Geo3DPoint.newShapeQuery("field",
-                                                      GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84, toRadians(50), toRadians(-97), Math.PI/180.)), 1).totalHits);
-    w.close();
-    r.close();
-    dir.close();
-  }
-
-  private static double toRadians(double degrees) {
-    return Math.PI*(degrees/360.0);
-  }
-
-  private static PlanetModel getPlanetModel() {
-    if (random().nextBoolean()) {
-      // Use one of the earth models:
-      if (random().nextBoolean()) {
-        return PlanetModel.WGS84;
-      } else {
-        return PlanetModel.SPHERE;
-      }
-    } else {
-      // Make a randomly squashed planet:
-      double oblateness = random().nextDouble() * 0.5 - 0.25;
-      return new PlanetModel(1.0 + oblateness, 1.0 - oblateness);
-    }
-  }
-
-  private static class Cell {
-    static int nextCellID;
-
-    final Cell parent;
-    final int cellID;
-    final int xMinEnc, xMaxEnc;
-    final int yMinEnc, yMaxEnc;
-    final int zMinEnc, zMaxEnc;
-    final int splitCount;
-
-    public Cell(Cell parent,
-                int xMinEnc, int xMaxEnc,
-                int yMinEnc, int yMaxEnc,
-                int zMinEnc, int zMaxEnc,
-                int splitCount) {
-      this.parent = parent;
-      this.xMinEnc = xMinEnc;
-      this.xMaxEnc = xMaxEnc;
-      this.yMinEnc = yMinEnc;
-      this.yMaxEnc = yMaxEnc;
-      this.zMinEnc = zMinEnc;
-      this.zMaxEnc = zMaxEnc;
-      this.cellID = nextCellID++;
-      this.splitCount = splitCount;
-    }
-
-    /** Returns true if the quantized point lies within this cell, inclusive on all bounds. */
-    public boolean contains(double planetMax, GeoPoint point) {
-      int docX = Geo3DUtil.encodeValue(planetMax, point.x);
-      int docY = Geo3DUtil.encodeValue(planetMax, point.y);
-      int docZ = Geo3DUtil.encodeValue(planetMax, point.z);
-
-      return docX >= xMinEnc && docX <= xMaxEnc &&
-        docY >= yMinEnc && docY <= yMaxEnc && 
-        docZ >= zMinEnc && docZ <= zMaxEnc;
-    }
-
-    @Override
-    public String toString() {
-      return "cell=" + cellID + (parent == null ? "" : " parentCellID=" + parent.cellID) + " x: " + xMinEnc + " TO " + xMaxEnc + ", y: " + yMinEnc + " TO " + yMaxEnc + ", z: " + zMinEnc + " TO " + zMaxEnc + ", splits: " + splitCount;
-    }
-  }
-
-  private static GeoPoint quantize(double planetMax, GeoPoint point) {
-    return new GeoPoint(Geo3DUtil.decodeValueCenter(planetMax, Geo3DUtil.encodeValue(planetMax, point.x)),
-                        Geo3DUtil.decodeValueCenter(planetMax, Geo3DUtil.encodeValue(planetMax, point.y)),
-                        Geo3DUtil.decodeValueCenter(planetMax, Geo3DUtil.encodeValue(planetMax, point.z)));
-  }
-
-  /** Tests consistency of GeoArea.getRelationship vs GeoShape.isWithin */
-  public void testGeo3DRelations() throws Exception {
-
-    PlanetModel planetModel = getPlanetModel();
-
-    int numDocs = atLeast(1000);
-    if (VERBOSE) {
-      System.out.println("TEST: " + numDocs + " docs");
-    }
-
-    GeoPoint[] docs = new GeoPoint[numDocs];
-    for(int docID=0;docID<numDocs;docID++) {
-      docs[docID] = new GeoPoint(planetModel, toRadians(randomLat()), toRadians(randomLon()));
-      if (VERBOSE) {
-        System.out.println("  doc=" + docID + ": " + docs[docID]);
-      }
-    }
-
-    double planetMax = planetModel.getMaximumMagnitude();
-
-    int iters = atLeast(10);
-
-    int recurseDepth = RandomInts.randomIntBetween(random(), 5, 15);
-
-    iters = atLeast(50);
-    
-    for(int iter=0;iter<iters;iter++) {
-      GeoShape shape = randomShape(planetModel);
-
-      StringWriter sw = new StringWriter();
-      PrintWriter log = new PrintWriter(sw, true);
-
-      if (VERBOSE) {
-        log.println("TEST: iter=" + iter + " shape=" + shape);
-      }
-
-      XYZBounds bounds = new XYZBounds();
-      shape.getBounds(bounds);
-
-      // Start with the root cell that fully contains the shape:
-      Cell root = new Cell(null,
-                           Geo3DUtil.encodeValueLenient(planetMax, bounds.getMinimumX()),
-                           Geo3DUtil.encodeValueLenient(planetMax, bounds.getMaximumX()),
-                           Geo3DUtil.encodeValueLenient(planetMax, bounds.getMinimumY()),
-                           Geo3DUtil.encodeValueLenient(planetMax, bounds.getMaximumY()),
-                           Geo3DUtil.encodeValueLenient(planetMax, bounds.getMinimumZ()),
-                           Geo3DUtil.encodeValueLenient(planetMax, bounds.getMaximumZ()),
-                           0);
-
-      if (VERBOSE) {
-        log.println("  root cell: " + root);
-      }
-
-      List<Cell> queue = new ArrayList<>();
-      queue.add(root);
-      Set<Integer> hits = new HashSet<>();
-
-      while (queue.size() > 0) {
-        Cell cell = queue.get(queue.size()-1);
-        queue.remove(queue.size()-1);
-        if (VERBOSE) {
-          log.println("  cycle: " + cell + " queue.size()=" + queue.size());
-        }
-
-        if (random().nextInt(10) == 7 || cell.splitCount > recurseDepth) {
-          if (VERBOSE) {
-            log.println("    leaf");
-          }
-          // Leaf cell: brute force check all docs that fall within this cell:
-          for(int docID=0;docID<numDocs;docID++) {
-            GeoPoint point = docs[docID];
-            if (cell.contains(planetMax, point)) {
-              if (shape.isWithin(quantize(planetMax, point))) {
-                if (VERBOSE) {
-                  log.println("    check doc=" + docID + ": match!");
-                }
-                hits.add(docID);
-              } else {
-                if (VERBOSE) {
-                  log.println("    check doc=" + docID + ": no match");
-                }
-              }
-            }
-          }
-        } else {
-          
-          GeoArea xyzSolid = GeoAreaFactory.makeGeoArea(planetModel,
-                                                        Geo3DUtil.decodeValueMin(planetMax, cell.xMinEnc), Geo3DUtil.decodeValueMax(planetMax, cell.xMaxEnc),
-                                                        Geo3DUtil.decodeValueMin(planetMax, cell.yMinEnc), Geo3DUtil.decodeValueMax(planetMax, cell.yMaxEnc),
-                                                        Geo3DUtil.decodeValueMin(planetMax, cell.zMinEnc), Geo3DUtil.decodeValueMax(planetMax, cell.zMaxEnc));
-
-          if (VERBOSE) {
-            log.println("    minx="+Geo3DUtil.decodeValueMin(planetMax, cell.xMinEnc)+" maxx="+Geo3DUtil.decodeValueMax(planetMax, cell.xMaxEnc)+
-              " miny="+Geo3DUtil.decodeValueMin(planetMax, cell.yMinEnc)+" maxy="+Geo3DUtil.decodeValueMax(planetMax, cell.yMaxEnc)+
-              " minz="+Geo3DUtil.decodeValueMin(planetMax, cell.zMinEnc)+" maxz="+Geo3DUtil.decodeValueMax(planetMax, cell.zMaxEnc));
-          }
-
-          switch (xyzSolid.getRelationship(shape)) {          
-          case GeoArea.CONTAINS:
-            // Shape fully contains the cell: blindly add all docs in this cell:
-            if (VERBOSE) {
-              log.println("    GeoArea.CONTAINS: now addAll");
-            }
-            for(int docID=0;docID<numDocs;docID++) {
-              if (cell.contains(planetMax, docs[docID])) {
-                if (VERBOSE) {
-                  log.println("    addAll doc=" + docID);
-                }
-                hits.add(docID);
-              }
-            }
-            continue;
-          case GeoArea.OVERLAPS:
-            if (VERBOSE) {
-              log.println("    GeoArea.OVERLAPS: keep splitting");
-            }
-            // They do overlap but neither contains the other:
-            //log.println("    crosses1");
-            break;
-          case GeoArea.WITHIN:
-            if (VERBOSE) {
-              log.println("    GeoArea.WITHIN: keep splitting");
-            }
-            // Cell fully contains the shape:
-            //log.println("    crosses2");
-            break;
-          case GeoArea.DISJOINT:
-            // They do not overlap at all: don't recurse on this cell
-            //log.println("    outside");
-            if (VERBOSE) {
-              log.println("    GeoArea.DISJOINT: drop this cell");
-              for(int docID=0;docID<numDocs;docID++) {
-                if (cell.contains(planetMax, docs[docID])) {
-                  if (VERBOSE) {
-                    log.println("    skip doc=" + docID);
-                  }
-                }
-              }
-            }
-            continue;
-          default:
-            assert false;
-          }
-
-          // Randomly split:
-          switch(random().nextInt(3)) {
-
-          case 0:
-            // Split on X:
-            {
-              int splitValue = RandomInts.randomIntBetween(random(), cell.xMinEnc, cell.xMaxEnc);
-              if (VERBOSE) {
-                log.println("    now split on x=" + splitValue);
-              }
-              Cell cell1 = new Cell(cell,
-                                 cell.xMinEnc, splitValue,
-                                 cell.yMinEnc, cell.yMaxEnc,
-                                 cell.zMinEnc, cell.zMaxEnc,
-                                 cell.splitCount+1);
-              Cell cell2 = new Cell(cell,
-                                 splitValue, cell.xMaxEnc,
-                                 cell.yMinEnc, cell.yMaxEnc,
-                                 cell.zMinEnc, cell.zMaxEnc,
-                                 cell.splitCount+1);
-              if (VERBOSE) {
-                log.println("    split cell1: " + cell1);
-                log.println("    split cell2: " + cell2);
-              }
-              queue.add(cell1);
-              queue.add(cell2);
-            }
-            break;
-
-          case 1:
-            // Split on Y:
-            {
-              int splitValue = RandomInts.randomIntBetween(random(), cell.yMinEnc, cell.yMaxEnc);
-              if (VERBOSE) {
-                log.println("    now split on y=" + splitValue);
-              }
-              Cell cell1 = new Cell(cell,
-                                 cell.xMinEnc, cell.xMaxEnc,
-                                 cell.yMinEnc, splitValue,
-                                 cell.zMinEnc, cell.zMaxEnc,
-                                 cell.splitCount+1);
-              Cell cell2 = new Cell(cell,
-                                 cell.xMinEnc, cell.xMaxEnc,
-                                 splitValue, cell.yMaxEnc,
-                                 cell.zMinEnc, cell.zMaxEnc,
-                                 cell.splitCount+1);
-              if (VERBOSE) {
-                log.println("    split cell1: " + cell1);
-                log.println("    split cell2: " + cell2);
-              }
-              queue.add(cell1);
-              queue.add(cell2);
-            }
-            break;
-
-          case 2:
-            // Split on Z:
-            {
-              int splitValue = RandomInts.randomIntBetween(random(), cell.zMinEnc, cell.zMaxEnc);
-              if (VERBOSE) {
-                log.println("    now split on z=" + splitValue);
-              }
-              Cell cell1 = new Cell(cell,
-                                 cell.xMinEnc, cell.xMaxEnc,
-                                 cell.yMinEnc, cell.yMaxEnc,
-                                 cell.zMinEnc, splitValue,
-                                 cell.splitCount+1);
-              Cell cell2 = new Cell(cell,
-                                 cell.xMinEnc, cell.xMaxEnc,
-                                 cell.yMinEnc, cell.yMaxEnc,
-                                 splitValue, cell.zMaxEnc,
-                                 cell.splitCount+1);
-              if (VERBOSE) {
-                log.println("    split cell1: " + cell1);
-                log.println("    split cell2: " + cell2);
-              }
-              queue.add(cell1);
-              queue.add(cell2);
-            }
-            break;
-          }
-        }
-      }
-
-      if (VERBOSE) {
-        log.println("  " + hits.size() + " hits");
-      }
-
-      // Done matching, now verify:
-      boolean fail = false;
-      for(int docID=0;docID<numDocs;docID++) {
-        GeoPoint point = docs[docID];
-        GeoPoint quantized = quantize(planetMax, point);
-        boolean expected = shape.isWithin(quantized);
-
-        if (expected != shape.isWithin(point)) {
-          // Quantization changed the result; skip testing this doc:
-          continue;
-        }
-
-        boolean actual = hits.contains(docID);
-        if (actual != expected) {
-          if (actual) {
-            log.println("doc=" + docID + " matched but should not");
-          } else {
-            log.println("doc=" + docID + " did not match but should");
-          }
-          log.println("  point=" + docs[docID]);
-          log.println("  quantized=" + quantize(planetMax, docs[docID]));
-          fail = true;
-        }
-      }
-
-      if (fail) {
-        System.out.print(sw.toString());
-        fail("invalid hits for shape=" + shape);
-      }
-    }
-  }
-
-  public void testRandomTiny() throws Exception {
-    // Make sure single-leaf-node case is OK:
-    doTestRandom(10);
-  }
-
-  public void testRandomMedium() throws Exception {
-    doTestRandom(10000);
-  }
-
-  @Nightly
-  public void testRandomBig() throws Exception {
-    doTestRandom(200000);
-  }
-
-  private void doTestRandom(int count) throws Exception {
-    int numPoints = atLeast(count);
-
-    if (VERBOSE) {
-      System.err.println("TEST: numPoints=" + numPoints);
-    }
-
-    double[] lats = new double[numPoints];
-    double[] lons = new double[numPoints];
-
-    boolean haveRealDoc = false;
-
-    for (int docID=0;docID<numPoints;docID++) {
-      int x = random().nextInt(20);
-      if (x == 17) {
-        // Some docs don't have a point:
-        lats[docID] = Double.NaN;
-        if (VERBOSE) {
-          System.err.println("  doc=" + docID + " is missing");
-        }
-        continue;
-      }
-
-      if (docID > 0 && x < 3 && haveRealDoc) {
-        int oldDocID;
-        while (true) {
-          oldDocID = random().nextInt(docID);
-          if (Double.isNaN(lats[oldDocID]) == false) {
-            break;
-          }
-        }
-            
-        if (x == 0) {
-          // Identical lat to old point
-          lats[docID] = lats[oldDocID];
-          lons[docID] = toRadians(randomLon());
-          if (VERBOSE) {
-            System.err.println("  doc=" + docID + " lat=" + lats[docID] + " lon=" + lons[docID] + " (same lat as doc=" + oldDocID + ")");
-          }
-        } else if (x == 1) {
-          // Identical lon to old point
-          lats[docID] = toRadians(randomLat());
-          lons[docID] = lons[oldDocID];
-          if (VERBOSE) {
-            System.err.println("  doc=" + docID + " lat=" + lats[docID] + " lon=" + lons[docID] + " (same lon as doc=" + oldDocID + ")");
-          }
-        } else {
-          assert x == 2;
-          // Fully identical point:
-          lats[docID] = lats[oldDocID];
-          lons[docID] = lons[oldDocID];
-          if (VERBOSE) {
-            System.err.println("  doc=" + docID + " lat=" + lats[docID] + " lon=" + lons[docID] + " (same lat/lon as doc=" + oldDocID + ")");
-          }
-        }
-      } else {
-        lats[docID] = toRadians(randomLat());
-        lons[docID] = toRadians(randomLon());
-        haveRealDoc = true;
-        if (VERBOSE) {
-          System.err.println("  doc=" + docID + " lat=" + lats[docID] + " lon=" + lons[docID]);
-        }
-      }
-    }
-
-    verify(lats, lons);
-  }
-
-  private static double randomLat() {
-    if (smallBBox) {
-      return 2.0 * (random().nextDouble()-0.5);
-    } else {
-      return -90 + 180.0 * random().nextDouble();
-    }
-  }
-
-  private static double randomLon() {
-    if (smallBBox) {
-      return 2.0 * (random().nextDouble()-0.5);
-    } else {
-      return -180 + 360.0 * random().nextDouble();
-    }
-  }
-
-  // Poached from Geo3dRptTest.randomShape:
-  private static GeoShape randomShape(PlanetModel planetModel) {
-    while (true) {
-      final int shapeType = random().nextInt(4);
-      switch (shapeType) {
-      case 0: {
-        // Polygons
-        final int vertexCount = random().nextInt(3) + 3;
-        final List<GeoPoint> geoPoints = new ArrayList<>();
-        while (geoPoints.size() < vertexCount) {
-          final GeoPoint gPt = new GeoPoint(planetModel, toRadians(randomLat()), toRadians(randomLon()));
-          geoPoints.add(gPt);
-        }
-        final int convexPointIndex = random().nextInt(vertexCount);       //If we get this wrong, hopefully we get IllegalArgumentException
-        try {
-          return GeoPolygonFactory.makeGeoPolygon(planetModel, geoPoints, convexPointIndex);
-        } 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
-
-        double lat = toRadians(randomLat());
-        double lon = toRadians(randomLon());
-
-        double angle;
-        if (smallBBox) {
-          angle = random().nextDouble() * Math.PI/360.0;
-        } else {
-          angle = random().nextDouble() * Math.PI/2.0;
-        }
-
-        try {
-          return GeoCircleFactory.makeGeoCircle(planetModel, lat, lon, angle);
-        } catch (IllegalArgumentException iae) {
-          // angle is too small; try again:
-          continue;
-        }
-      }
-
-      case 2: {
-        // Rectangles
-        double lat0 = toRadians(randomLat());
-        double lat1 = toRadians(randomLat());
-        if (lat1 < lat0) {
-          double x = lat0;
-          lat0 = lat1;
-          lat1 = x;
-        }
-        double lon0 = toRadians(randomLon());
-        double lon1 = toRadians(randomLon());
-        if (lon1 < lon0) {
-          double x = lon0;
-          lon0 = lon1;
-          lon1 = x;
-        }
-
-        return GeoBBoxFactory.makeGeoBBox(planetModel, lat1, lat0, lon0, lon1);
-      }
-
-      case 3: {
-        // Paths
-        final int pointCount = random().nextInt(5) + 1;
-        final double width = toRadians(random().nextInt(89)+1);
-        try {
-          final GeoPath path = new GeoPath(planetModel, width);
-          for (int i = 0; i < pointCount; i++) {
-            path.addPoint(toRadians(randomLat()), toRadians(randomLon()));
-          }
-          path.done();
-          return path;
-        } 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");
-      }
-    }
-  }
-
-  private static void verify(double[] lats, double[] lons) throws Exception {
-    IndexWriterConfig iwc = newIndexWriterConfig();
-
-    // Else we can get O(N^2) merging:
-    int mbd = iwc.getMaxBufferedDocs();
-    if (mbd != -1 && mbd < lats.length/100) {
-      iwc.setMaxBufferedDocs(lats.length/100);
-    }
-    iwc.setCodec(getCodec());
-    Directory dir;
-    if (lats.length > 100000) {
-      dir = newFSDirectory(createTempDir("TestBKDTree"));
-    } else {
-      dir = getDirectory();
-    }
-    Set<Integer> deleted = new HashSet<>();
-    // RandomIndexWriter is too slow here:
-    IndexWriter w = new IndexWriter(dir, iwc);
-    for(int id=0;id<lats.length;id++) {
-      Document doc = new Document();
-      doc.add(newStringField("id", ""+id, Field.Store.NO));
-      doc.add(new NumericDocValuesField("id", id));
-      if (Double.isNaN(lats[id]) == false) {
-        doc.add(new Geo3DPoint("point", lats[id], lons[id]));
-      }
-      w.addDocument(doc);
-      if (id > 0 && random().nextInt(100) == 42) {
-        int idToDelete = random().nextInt(id);
-        w.deleteDocuments(new Term("id", ""+idToDelete));
-        deleted.add(idToDelete);
-        if (VERBOSE) {
-          System.err.println("  delete id=" + idToDelete);
-        }
-      }
-    }
-    if (random().nextBoolean()) {
-      w.forceMerge(1);
-    }
-    final IndexReader r = DirectoryReader.open(w);
-    w.close();
-
-    // We can't wrap with "exotic" readers because the geo3d query must see the Geo3DDVFormat:
-    IndexSearcher s = newSearcher(r, false);
-
-    int numThreads = TestUtil.nextInt(random(), 2, 5);
-
-    List<Thread> threads = new ArrayList<>();
-    final int iters = atLeast(100);
-
-    final CountDownLatch startingGun = new CountDownLatch(1);
-    final AtomicBoolean failed = new AtomicBoolean();
-
-    for(int i=0;i<numThreads;i++) {
-      Thread thread = new Thread() {
-          @Override
-          public void run() {
-            try {
-              _run();
-            } catch (Exception e) {
-              failed.set(true);
-              throw new RuntimeException(e);
-            }
-          }
-
-          private void _run() throws Exception {
-            startingGun.await();
-
-            NumericDocValues docIDToID = MultiDocValues.getNumericValues(r, "id");
-
-            for (int iter=0;iter<iters && failed.get() == false;iter++) {
-
-              GeoShape shape = randomShape(PlanetModel.WGS84);
-
-              if (VERBOSE) {
-                System.err.println("\n" + Thread.currentThread() + ": TEST: iter=" + iter + " shape="+shape);
-              }
-              
-              Query query = Geo3DPoint.newShapeQuery("point", shape);
-
-              if (VERBOSE) {
-                System.err.println("  using query: " + query);
-              }
-
-              final FixedBitSet hits = new FixedBitSet(r.maxDoc());
-
-              s.search(query, new SimpleCollector() {
-
-                  private int docBase;
-
-                  @Override
-                  public boolean needsScores() {
-                    return false;
-                  }
-
-                  @Override
-                  protected void doSetNextReader(LeafReaderContext context) throws IOException {
-                    docBase = context.docBase;
-                  }
-
-                  @Override
-                  public void collect(int doc) {
-                    hits.set(docBase+doc);
-                  }
-                });
-
-              if (VERBOSE) {
-                System.err.println("  hitCount: " + hits.cardinality());
-              }
-      
-              for(int docID=0;docID<r.maxDoc();docID++) {
-                int id = (int) docIDToID.get(docID);
-                if (Double.isNaN(lats[id]) == false) {
-
-                  // Accurate point:
-                  GeoPoint point1 = new GeoPoint(PlanetModel.WGS84, lats[id], lons[id]);
-
-                  // Quantized point (32 bits per dim):
-                  GeoPoint point2 = quantize(PlanetModel.WGS84.getMaximumMagnitude(), point1);
-
-                  if (shape.isWithin(point1) != shape.isWithin(point2)) {
-                    if (VERBOSE) {
-                      System.out.println("  skip checking docID=" + docID + " quantization changed the expected result from " + shape.isWithin(point1) + " to " + shape.isWithin(point2));
-                    }
-                    continue;
-                  }
-
-                  boolean expected = ((deleted.contains(id) == false) && shape.isWithin(point2));
-                  if (hits.get(docID) != expected) {
-                    fail(Thread.currentThread().getName() + ": iter=" + iter + " id=" + id + " docID=" + docID + " lat=" + lats[id] + " lon=" + lons[id] + " expected " + expected + " but got: " + hits.get(docID) + " deleted?=" + deleted.contains(id) + "\n  point1=" + point1 + ", iswithin="+shape.isWithin(point1)+"\n  point2=" + point2 + ", iswithin="+shape.isWithin(point2) + "\n  query=" + query);
-                  }
-                } else {
-                  assertFalse(hits.get(docID));
-                }
-
-              }
-            }
-          }
-        };
-      thread.setName("T" + i);
-      thread.start();
-      threads.add(thread);
-    }
-    startingGun.countDown();
-    for(Thread thread : threads) {
-      thread.join();
-    }
-    IOUtils.close(r, dir);
-  }
-
-  public void testToString() {
-    Geo3DPoint point = new Geo3DPoint("point", toRadians(44.244272), toRadians(7.769736));
-    assertEquals("Geo3DPoint <point: x=0.9248467864160119 y=0.06280434265368656 z=0.37682349005486243>", point.toString());
-  }
-
-  public void testShapeQueryToString() {
-    assertEquals("PointInGeo3DShapeQuery: field=point: Shape: GeoStandardCircle: {planetmodel=PlanetModel.WGS84, center=[lat=0.3861041107739683, lon=0.06780373760536706], radius=0.1(5.729577951308232)}",
-                 Geo3DPoint.newShapeQuery("point", GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84, toRadians(44.244272), toRadians(7.769736), 0.1)).toString());
-  }
-
-  private static Directory getDirectory() {     
-    return newDirectory();
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/test/org/apache/lucene/geo3d/XYZSolidTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/XYZSolidTest.java b/lucene/spatial3d/src/test/org/apache/lucene/geo3d/XYZSolidTest.java
deleted file mode 100644
index 876a525..0000000
--- a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/XYZSolidTest.java
+++ /dev/null
@@ -1,220 +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.geo3d;
-
-import org.apache.lucene.util.LuceneTestCase;
-import org.junit.Test;
-
-public class XYZSolidTest extends LuceneTestCase {
-
-  @Test
-  public void testNonDegenerateRelationships() {
-    XYZSolid s;
-    GeoShape shape;
-    // Something bigger than the world
-    s = new StandardXYZSolid(PlanetModel.SPHERE, -2.0, 2.0, -2.0, 2.0, -2.0, 2.0);
-    // Any shape, except whole world, should be within.
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.WITHIN, s.getRelationship(shape));
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    // An XYZSolid represents a surface shape, which when larger than the world is in fact
-    // the entire world, so it should overlap the world.
-    assertEquals(GeoArea.OVERLAPS, s.getRelationship(shape));
-
-    // Something overlapping the world on only one side
-    s = new StandardXYZSolid(PlanetModel.SPHERE, -2.0, 0.0, -2.0, 2.0, -2.0, 2.0);
-    // Some things should be disjoint...
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, s.getRelationship(shape));
-    // And, some things should be within... 
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI, 0.1);
-    assertEquals(GeoArea.WITHIN, s.getRelationship(shape));
-    // And, some things should overlap.
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI * 0.5, 0.1);
-    assertEquals(GeoArea.OVERLAPS, s.getRelationship(shape));
-
-    // Partial world should be contained by GeoWorld object...
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.CONTAINS, s.getRelationship(shape));
-    
-    // Something inside the world
-    s = new StandardXYZSolid(PlanetModel.SPHERE, -0.1, 0.1, -0.1, 0.1, -0.1, 0.1);
-    // All shapes should be disjoint
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, s.getRelationship(shape));
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.DISJOINT, s.getRelationship(shape));
-    
-  }
-
-  @Test
-  public void testDegenerateRelationships() {
-    GeoArea solid;
-    GeoShape shape;
-    
-    // Basic test of the factory method - non-degenerate
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, -2.0, 2.0, -2.0, 2.0, -2.0, 2.0);
-    // Any shape, except whole world, should be within.
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.WITHIN, solid.getRelationship(shape));
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    // An XYZSolid represents a surface shape, which when larger than the world is in fact
-    // the entire world, so it should overlap the world.
-    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
-
-    // Build a degenerate point, not on sphere
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
-    // disjoint with everything?
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-
-    // Build a degenerate point that IS on the sphere
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0);
-    // inside everything that it touches?
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-
-    // Build a shape degenerate in (x,y), which has no points on sphere
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, 0.0, 0.0, -0.1, 0.1);
-    // disjoint with everything?
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-
-    // Build a shape degenerate in (x,y) which has one point on sphere
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, 0.0, 0.0, -0.1, 1.1);
-    // inside everything that it touches?
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, Math.PI * 0.5, 0.0, 0.1);
-    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-
-    // Build a shape degenerate in (x,y) which has two points on sphere
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, 0.0, 0.0, -1.1, 1.1);
-    // inside everything that it touches?
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, Math.PI * 0.5, 0.0, 0.1);
-    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0, 0.1);
-    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
-    
-    // Build a shape degenerate in (x,z), which has no points on sphere
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, -0.1, 0.1, 0.0, 0.0);
-    // disjoint with everything?
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-
-    // Build a shape degenerate in (x,z) which has one point on sphere
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, -0.1, 1.1, 0.0, 0.0);
-    // inside everything that it touches?
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI * 0.5, 0.1);
-    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, -Math.PI * 0.5, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-
-    // Build a shape degenerate in (x,y) which has two points on sphere
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, -1.1, 1.1, 0.0, 0.0);
-    // inside everything that it touches?
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI * 0.5, 0.1);
-    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, -Math.PI * 0.5, 0.1);
-    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
-
-    // MHL for y-z check
-    
-    // Build a shape that is degenerate in x, which has zero points intersecting sphere
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, -0.1, 0.1, -0.1, 0.1);
-    // disjoint with everything?
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-
-    // Build a shape that is degenerate in x, which has zero points intersecting sphere, second variation
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, -0.1, 0.1, 1.1, 1.2);
-    // disjoint with everything?
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-
-    // Build a shape that is disjoint in X but intersects sphere in a complete circle
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, -1.1, 1.1, -1.1, 1.1);
-    // inside everything that it touches?
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI * 0.5, 0.1);
-    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, -Math.PI * 0.5, 0.1);
-    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, Math.PI * 0.5, 0.0, 0.1);
-    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0, 0.1);
-    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
-
-    // Build a shape that is disjoint in X but intersects sphere in a half circle in Y
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, 0.0, 1.1, -1.1, 1.1);
-    // inside everything that it touches?
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI * 0.5, 0.1);
-    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, -Math.PI * 0.5, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, Math.PI * 0.5, 0.0, 0.1);
-    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0, 0.1);
-    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
-
-    // MHL for degenerate Y
-    // MHL for degenerate Z
-    
-  }
-  
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/TestGeo3DPoint.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/TestGeo3DPoint.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/TestGeo3DPoint.java
new file mode 100644
index 0000000..a4d8ed1
--- /dev/null
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/TestGeo3DPoint.java
@@ -0,0 +1,810 @@
+/*
+ * 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.spatial3d;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.lucene.codecs.Codec;
+import org.apache.lucene.codecs.FilterCodec;
+import org.apache.lucene.codecs.PointsFormat;
+import org.apache.lucene.codecs.PointsReader;
+import org.apache.lucene.codecs.PointsWriter;
+import org.apache.lucene.codecs.lucene60.Lucene60PointsReader;
+import org.apache.lucene.codecs.lucene60.Lucene60PointsWriter;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.NumericDocValuesField;
+import org.apache.lucene.spatial3d.geom.GeoArea;
+import org.apache.lucene.spatial3d.geom.GeoAreaFactory;
+import org.apache.lucene.spatial3d.geom.GeoBBoxFactory;
+import org.apache.lucene.spatial3d.geom.GeoCircleFactory;
+import org.apache.lucene.spatial3d.geom.GeoPath;
+import org.apache.lucene.spatial3d.geom.GeoPoint;
+import org.apache.lucene.spatial3d.geom.GeoPolygonFactory;
+import org.apache.lucene.spatial3d.geom.GeoShape;
+import org.apache.lucene.spatial3d.geom.PlanetModel;
+import org.apache.lucene.spatial3d.geom.XYZBounds;
+import org.apache.lucene.index.DirectoryReader;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.IndexWriterConfig;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.MultiDocValues;
+import org.apache.lucene.index.NumericDocValues;
+import org.apache.lucene.index.SegmentReadState;
+import org.apache.lucene.index.SegmentWriteState;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.SimpleCollector;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.util.FixedBitSet;
+import org.apache.lucene.util.IOUtils;
+import org.apache.lucene.util.LuceneTestCase;
+import org.apache.lucene.util.TestUtil;
+import org.junit.BeforeClass;
+
+import com.carrotsearch.randomizedtesting.generators.RandomInts;
+
+public class TestGeo3DPoint extends LuceneTestCase {
+
+  private static boolean smallBBox;
+  
+  @BeforeClass
+  public static void beforeClass() {
+    smallBBox = random().nextBoolean();
+    if (VERBOSE) {
+      System.err.println("TEST: smallBBox=" + smallBBox);
+    }
+  }
+
+  private static Codec getCodec() {
+    if (Codec.getDefault().getName().equals("Lucene60")) {
+      int maxPointsInLeafNode = TestUtil.nextInt(random(), 16, 2048);
+      double maxMBSortInHeap = 3.0 + (3*random().nextDouble());
+      if (VERBOSE) {
+        System.out.println("TEST: using Lucene60PointsFormat with maxPointsInLeafNode=" + maxPointsInLeafNode + " and maxMBSortInHeap=" + maxMBSortInHeap);
+      }
+
+      return new FilterCodec("Lucene60", Codec.getDefault()) {
+        @Override
+        public PointsFormat pointsFormat() {
+          return new PointsFormat() {
+            @Override
+            public PointsWriter fieldsWriter(SegmentWriteState writeState) throws IOException {
+              return new Lucene60PointsWriter(writeState, maxPointsInLeafNode, maxMBSortInHeap);
+            }
+
+            @Override
+            public PointsReader fieldsReader(SegmentReadState readState) throws IOException {
+              return new Lucene60PointsReader(readState);
+            }
+          };
+        }
+      };
+    } else {
+      return Codec.getDefault();
+    }
+  }
+
+  public void testBasic() throws Exception {
+    Directory dir = getDirectory();
+    IndexWriterConfig iwc = newIndexWriterConfig();
+    iwc.setCodec(getCodec());
+    IndexWriter w = new IndexWriter(dir, iwc);
+    Document doc = new Document();
+    doc.add(new Geo3DPoint("field", toRadians(50.7345267), toRadians(-97.5303555)));
+    w.addDocument(doc);
+    IndexReader r = DirectoryReader.open(w);
+    // We can't wrap with "exotic" readers because the query must see the BKD3DDVFormat:
+    IndexSearcher s = newSearcher(r, false);
+    assertEquals(1, s.search(Geo3DPoint.newShapeQuery("field",
+                                                      GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84, toRadians(50), toRadians(-97), Math.PI/180.)), 1).totalHits);
+    w.close();
+    r.close();
+    dir.close();
+  }
+
+  private static double toRadians(double degrees) {
+    return Math.PI*(degrees/360.0);
+  }
+
+  private static PlanetModel getPlanetModel() {
+    if (random().nextBoolean()) {
+      // Use one of the earth models:
+      if (random().nextBoolean()) {
+        return PlanetModel.WGS84;
+      } else {
+        return PlanetModel.SPHERE;
+      }
+    } else {
+      // Make a randomly squashed planet:
+      double oblateness = random().nextDouble() * 0.5 - 0.25;
+      return new PlanetModel(1.0 + oblateness, 1.0 - oblateness);
+    }
+  }
+
+  private static class Cell {
+    static int nextCellID;
+
+    final Cell parent;
+    final int cellID;
+    final int xMinEnc, xMaxEnc;
+    final int yMinEnc, yMaxEnc;
+    final int zMinEnc, zMaxEnc;
+    final int splitCount;
+
+    public Cell(Cell parent,
+                int xMinEnc, int xMaxEnc,
+                int yMinEnc, int yMaxEnc,
+                int zMinEnc, int zMaxEnc,
+                int splitCount) {
+      this.parent = parent;
+      this.xMinEnc = xMinEnc;
+      this.xMaxEnc = xMaxEnc;
+      this.yMinEnc = yMinEnc;
+      this.yMaxEnc = yMaxEnc;
+      this.zMinEnc = zMinEnc;
+      this.zMaxEnc = zMaxEnc;
+      this.cellID = nextCellID++;
+      this.splitCount = splitCount;
+    }
+
+    /** Returns true if the quantized point lies within this cell, inclusive on all bounds. */
+    public boolean contains(double planetMax, GeoPoint point) {
+      int docX = Geo3DUtil.encodeValue(planetMax, point.x);
+      int docY = Geo3DUtil.encodeValue(planetMax, point.y);
+      int docZ = Geo3DUtil.encodeValue(planetMax, point.z);
+
+      return docX >= xMinEnc && docX <= xMaxEnc &&
+        docY >= yMinEnc && docY <= yMaxEnc && 
+        docZ >= zMinEnc && docZ <= zMaxEnc;
+    }
+
+    @Override
+    public String toString() {
+      return "cell=" + cellID + (parent == null ? "" : " parentCellID=" + parent.cellID) + " x: " + xMinEnc + " TO " + xMaxEnc + ", y: " + yMinEnc + " TO " + yMaxEnc + ", z: " + zMinEnc + " TO " + zMaxEnc + ", splits: " + splitCount;
+    }
+  }
+
+  private static GeoPoint quantize(double planetMax, GeoPoint point) {
+    return new GeoPoint(Geo3DUtil.decodeValueCenter(planetMax, Geo3DUtil.encodeValue(planetMax, point.x)),
+                        Geo3DUtil.decodeValueCenter(planetMax, Geo3DUtil.encodeValue(planetMax, point.y)),
+                        Geo3DUtil.decodeValueCenter(planetMax, Geo3DUtil.encodeValue(planetMax, point.z)));
+  }
+
+  /** Tests consistency of GeoArea.getRelationship vs GeoShape.isWithin */
+  public void testGeo3DRelations() throws Exception {
+
+    PlanetModel planetModel = getPlanetModel();
+
+    int numDocs = atLeast(1000);
+    if (VERBOSE) {
+      System.out.println("TEST: " + numDocs + " docs");
+    }
+
+    GeoPoint[] docs = new GeoPoint[numDocs];
+    for(int docID=0;docID<numDocs;docID++) {
+      docs[docID] = new GeoPoint(planetModel, toRadians(randomLat()), toRadians(randomLon()));
+      if (VERBOSE) {
+        System.out.println("  doc=" + docID + ": " + docs[docID]);
+      }
+    }
+
+    double planetMax = planetModel.getMaximumMagnitude();
+
+    int iters = atLeast(10);
+
+    int recurseDepth = RandomInts.randomIntBetween(random(), 5, 15);
+
+    iters = atLeast(50);
+    
+    for(int iter=0;iter<iters;iter++) {
+      GeoShape shape = randomShape(planetModel);
+
+      StringWriter sw = new StringWriter();
+      PrintWriter log = new PrintWriter(sw, true);
+
+      if (VERBOSE) {
+        log.println("TEST: iter=" + iter + " shape=" + shape);
+      }
+
+      XYZBounds bounds = new XYZBounds();
+      shape.getBounds(bounds);
+
+      // Start with the root cell that fully contains the shape:
+      Cell root = new Cell(null,
+                           Geo3DUtil.encodeValueLenient(planetMax, bounds.getMinimumX()),
+                           Geo3DUtil.encodeValueLenient(planetMax, bounds.getMaximumX()),
+                           Geo3DUtil.encodeValueLenient(planetMax, bounds.getMinimumY()),
+                           Geo3DUtil.encodeValueLenient(planetMax, bounds.getMaximumY()),
+                           Geo3DUtil.encodeValueLenient(planetMax, bounds.getMinimumZ()),
+                           Geo3DUtil.encodeValueLenient(planetMax, bounds.getMaximumZ()),
+                           0);
+
+      if (VERBOSE) {
+        log.println("  root cell: " + root);
+      }
+
+      List<Cell> queue = new ArrayList<>();
+      queue.add(root);
+      Set<Integer> hits = new HashSet<>();
+
+      while (queue.size() > 0) {
+        Cell cell = queue.get(queue.size()-1);
+        queue.remove(queue.size()-1);
+        if (VERBOSE) {
+          log.println("  cycle: " + cell + " queue.size()=" + queue.size());
+        }
+
+        if (random().nextInt(10) == 7 || cell.splitCount > recurseDepth) {
+          if (VERBOSE) {
+            log.println("    leaf");
+          }
+          // Leaf cell: brute force check all docs that fall within this cell:
+          for(int docID=0;docID<numDocs;docID++) {
+            GeoPoint point = docs[docID];
+            if (cell.contains(planetMax, point)) {
+              if (shape.isWithin(quantize(planetMax, point))) {
+                if (VERBOSE) {
+                  log.println("    check doc=" + docID + ": match!");
+                }
+                hits.add(docID);
+              } else {
+                if (VERBOSE) {
+                  log.println("    check doc=" + docID + ": no match");
+                }
+              }
+            }
+          }
+        } else {
+          
+          GeoArea xyzSolid = GeoAreaFactory.makeGeoArea(planetModel,
+                                                        Geo3DUtil.decodeValueMin(planetMax, cell.xMinEnc), Geo3DUtil.decodeValueMax(planetMax, cell.xMaxEnc),
+                                                        Geo3DUtil.decodeValueMin(planetMax, cell.yMinEnc), Geo3DUtil.decodeValueMax(planetMax, cell.yMaxEnc),
+                                                        Geo3DUtil.decodeValueMin(planetMax, cell.zMinEnc), Geo3DUtil.decodeValueMax(planetMax, cell.zMaxEnc));
+
+          if (VERBOSE) {
+            log.println("    minx="+Geo3DUtil.decodeValueMin(planetMax, cell.xMinEnc)+" maxx="+Geo3DUtil.decodeValueMax(planetMax, cell.xMaxEnc)+
+              " miny="+Geo3DUtil.decodeValueMin(planetMax, cell.yMinEnc)+" maxy="+Geo3DUtil.decodeValueMax(planetMax, cell.yMaxEnc)+
+              " minz="+Geo3DUtil.decodeValueMin(planetMax, cell.zMinEnc)+" maxz="+Geo3DUtil.decodeValueMax(planetMax, cell.zMaxEnc));
+          }
+
+          switch (xyzSolid.getRelationship(shape)) {          
+          case GeoArea.CONTAINS:
+            // Shape fully contains the cell: blindly add all docs in this cell:
+            if (VERBOSE) {
+              log.println("    GeoArea.CONTAINS: now addAll");
+            }
+            for(int docID=0;docID<numDocs;docID++) {
+              if (cell.contains(planetMax, docs[docID])) {
+                if (VERBOSE) {
+                  log.println("    addAll doc=" + docID);
+                }
+                hits.add(docID);
+              }
+            }
+            continue;
+          case GeoArea.OVERLAPS:
+            if (VERBOSE) {
+              log.println("    GeoArea.OVERLAPS: keep splitting");
+            }
+            // They do overlap but neither contains the other:
+            //log.println("    crosses1");
+            break;
+          case GeoArea.WITHIN:
+            if (VERBOSE) {
+              log.println("    GeoArea.WITHIN: keep splitting");
+            }
+            // Cell fully contains the shape:
+            //log.println("    crosses2");
+            break;
+          case GeoArea.DISJOINT:
+            // They do not overlap at all: don't recurse on this cell
+            //log.println("    outside");
+            if (VERBOSE) {
+              log.println("    GeoArea.DISJOINT: drop this cell");
+              for(int docID=0;docID<numDocs;docID++) {
+                if (cell.contains(planetMax, docs[docID])) {
+                  if (VERBOSE) {
+                    log.println("    skip doc=" + docID);
+                  }
+                }
+              }
+            }
+            continue;
+          default:
+            assert false;
+          }
+
+          // Randomly split:
+          switch(random().nextInt(3)) {
+
+          case 0:
+            // Split on X:
+            {
+              int splitValue = RandomInts.randomIntBetween(random(), cell.xMinEnc, cell.xMaxEnc);
+              if (VERBOSE) {
+                log.println("    now split on x=" + splitValue);
+              }
+              Cell cell1 = new Cell(cell,
+                                 cell.xMinEnc, splitValue,
+                                 cell.yMinEnc, cell.yMaxEnc,
+                                 cell.zMinEnc, cell.zMaxEnc,
+                                 cell.splitCount+1);
+              Cell cell2 = new Cell(cell,
+                                 splitValue, cell.xMaxEnc,
+                                 cell.yMinEnc, cell.yMaxEnc,
+                                 cell.zMinEnc, cell.zMaxEnc,
+                                 cell.splitCount+1);
+              if (VERBOSE) {
+                log.println("    split cell1: " + cell1);
+                log.println("    split cell2: " + cell2);
+              }
+              queue.add(cell1);
+              queue.add(cell2);
+            }
+            break;
+
+          case 1:
+            // Split on Y:
+            {
+              int splitValue = RandomInts.randomIntBetween(random(), cell.yMinEnc, cell.yMaxEnc);
+              if (VERBOSE) {
+                log.println("    now split on y=" + splitValue);
+              }
+              Cell cell1 = new Cell(cell,
+                                 cell.xMinEnc, cell.xMaxEnc,
+                                 cell.yMinEnc, splitValue,
+                                 cell.zMinEnc, cell.zMaxEnc,
+                                 cell.splitCount+1);
+              Cell cell2 = new Cell(cell,
+                                 cell.xMinEnc, cell.xMaxEnc,
+                                 splitValue, cell.yMaxEnc,
+                                 cell.zMinEnc, cell.zMaxEnc,
+                                 cell.splitCount+1);
+              if (VERBOSE) {
+                log.println("    split cell1: " + cell1);
+                log.println("    split cell2: " + cell2);
+              }
+              queue.add(cell1);
+              queue.add(cell2);
+            }
+            break;
+
+          case 2:
+            // Split on Z:
+            {
+              int splitValue = RandomInts.randomIntBetween(random(), cell.zMinEnc, cell.zMaxEnc);
+              if (VERBOSE) {
+                log.println("    now split on z=" + splitValue);
+              }
+              Cell cell1 = new Cell(cell,
+                                 cell.xMinEnc, cell.xMaxEnc,
+                                 cell.yMinEnc, cell.yMaxEnc,
+                                 cell.zMinEnc, splitValue,
+                                 cell.splitCount+1);
+              Cell cell2 = new Cell(cell,
+                                 cell.xMinEnc, cell.xMaxEnc,
+                                 cell.yMinEnc, cell.yMaxEnc,
+                                 splitValue, cell.zMaxEnc,
+                                 cell.splitCount+1);
+              if (VERBOSE) {
+                log.println("    split cell1: " + cell1);
+                log.println("    split cell2: " + cell2);
+              }
+              queue.add(cell1);
+              queue.add(cell2);
+            }
+            break;
+          }
+        }
+      }
+
+      if (VERBOSE) {
+        log.println("  " + hits.size() + " hits");
+      }
+
+      // Done matching, now verify:
+      boolean fail = false;
+      for(int docID=0;docID<numDocs;docID++) {
+        GeoPoint point = docs[docID];
+        GeoPoint quantized = quantize(planetMax, point);
+        boolean expected = shape.isWithin(quantized);
+
+        if (expected != shape.isWithin(point)) {
+          // Quantization changed the result; skip testing this doc:
+          continue;
+        }
+
+        boolean actual = hits.contains(docID);
+        if (actual != expected) {
+          if (actual) {
+            log.println("doc=" + docID + " matched but should not");
+          } else {
+            log.println("doc=" + docID + " did not match but should");
+          }
+          log.println("  point=" + docs[docID]);
+          log.println("  quantized=" + quantize(planetMax, docs[docID]));
+          fail = true;
+        }
+      }
+
+      if (fail) {
+        System.out.print(sw.toString());
+        fail("invalid hits for shape=" + shape);
+      }
+    }
+  }
+
+  public void testRandomTiny() throws Exception {
+    // Make sure single-leaf-node case is OK:
+    doTestRandom(10);
+  }
+
+  public void testRandomMedium() throws Exception {
+    doTestRandom(10000);
+  }
+
+  @Nightly
+  public void testRandomBig() throws Exception {
+    doTestRandom(200000);
+  }
+
+  private void doTestRandom(int count) throws Exception {
+    int numPoints = atLeast(count);
+
+    if (VERBOSE) {
+      System.err.println("TEST: numPoints=" + numPoints);
+    }
+
+    double[] lats = new double[numPoints];
+    double[] lons = new double[numPoints];
+
+    boolean haveRealDoc = false;
+
+    for (int docID=0;docID<numPoints;docID++) {
+      int x = random().nextInt(20);
+      if (x == 17) {
+        // Some docs don't have a point:
+        lats[docID] = Double.NaN;
+        if (VERBOSE) {
+          System.err.println("  doc=" + docID + " is missing");
+        }
+        continue;
+      }
+
+      if (docID > 0 && x < 3 && haveRealDoc) {
+        int oldDocID;
+        while (true) {
+          oldDocID = random().nextInt(docID);
+          if (Double.isNaN(lats[oldDocID]) == false) {
+            break;
+          }
+        }
+            
+        if (x == 0) {
+          // Identical lat to old point
+          lats[docID] = lats[oldDocID];
+          lons[docID] = toRadians(randomLon());
+          if (VERBOSE) {
+            System.err.println("  doc=" + docID + " lat=" + lats[docID] + " lon=" + lons[docID] + " (same lat as doc=" + oldDocID + ")");
+          }
+        } else if (x == 1) {
+          // Identical lon to old point
+          lats[docID] = toRadians(randomLat());
+          lons[docID] = lons[oldDocID];
+          if (VERBOSE) {
+            System.err.println("  doc=" + docID + " lat=" + lats[docID] + " lon=" + lons[docID] + " (same lon as doc=" + oldDocID + ")");
+          }
+        } else {
+          assert x == 2;
+          // Fully identical point:
+          lats[docID] = lats[oldDocID];
+          lons[docID] = lons[oldDocID];
+          if (VERBOSE) {
+            System.err.println("  doc=" + docID + " lat=" + lats[docID] + " lon=" + lons[docID] + " (same lat/lon as doc=" + oldDocID + ")");
+          }
+        }
+      } else {
+        lats[docID] = toRadians(randomLat());
+        lons[docID] = toRadians(randomLon());
+        haveRealDoc = true;
+        if (VERBOSE) {
+          System.err.println("  doc=" + docID + " lat=" + lats[docID] + " lon=" + lons[docID]);
+        }
+      }
+    }
+
+    verify(lats, lons);
+  }
+
+  private static double randomLat() {
+    if (smallBBox) {
+      return 2.0 * (random().nextDouble()-0.5);
+    } else {
+      return -90 + 180.0 * random().nextDouble();
+    }
+  }
+
+  private static double randomLon() {
+    if (smallBBox) {
+      return 2.0 * (random().nextDouble()-0.5);
+    } else {
+      return -180 + 360.0 * random().nextDouble();
+    }
+  }
+
+  // Poached from Geo3dRptTest.randomShape:
+  private static GeoShape randomShape(PlanetModel planetModel) {
+    while (true) {
+      final int shapeType = random().nextInt(4);
+      switch (shapeType) {
+      case 0: {
+        // Polygons
+        final int vertexCount = random().nextInt(3) + 3;
+        final List<GeoPoint> geoPoints = new ArrayList<>();
+        while (geoPoints.size() < vertexCount) {
+          final GeoPoint gPt = new GeoPoint(planetModel, toRadians(randomLat()), toRadians(randomLon()));
+          geoPoints.add(gPt);
+        }
+        final int convexPointIndex = random().nextInt(vertexCount);       //If we get this wrong, hopefully we get IllegalArgumentException
+        try {
+          return GeoPolygonFactory.makeGeoPolygon(planetModel, geoPoints, convexPointIndex);
+        } 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
+
+        double lat = toRadians(randomLat());
+        double lon = toRadians(randomLon());
+
+        double angle;
+        if (smallBBox) {
+          angle = random().nextDouble() * Math.PI/360.0;
+        } else {
+          angle = random().nextDouble() * Math.PI/2.0;
+        }
+
+        try {
+          return GeoCircleFactory.makeGeoCircle(planetModel, lat, lon, angle);
+        } catch (IllegalArgumentException iae) {
+          // angle is too small; try again:
+          continue;
+        }
+      }
+
+      case 2: {
+        // Rectangles
+        double lat0 = toRadians(randomLat());
+        double lat1 = toRadians(randomLat());
+        if (lat1 < lat0) {
+          double x = lat0;
+          lat0 = lat1;
+          lat1 = x;
+        }
+        double lon0 = toRadians(randomLon());
+        double lon1 = toRadians(randomLon());
+        if (lon1 < lon0) {
+          double x = lon0;
+          lon0 = lon1;
+          lon1 = x;
+        }
+
+        return GeoBBoxFactory.makeGeoBBox(planetModel, lat1, lat0, lon0, lon1);
+      }
+
+      case 3: {
+        // Paths
+        final int pointCount = random().nextInt(5) + 1;
+        final double width = toRadians(random().nextInt(89)+1);
+        try {
+          final GeoPath path = new GeoPath(planetModel, width);
+          for (int i = 0; i < pointCount; i++) {
+            path.addPoint(toRadians(randomLat()), toRadians(randomLon()));
+          }
+          path.done();
+          return path;
+        } 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");
+      }
+    }
+  }
+
+  private static void verify(double[] lats, double[] lons) throws Exception {
+    IndexWriterConfig iwc = newIndexWriterConfig();
+
+    // Else we can get O(N^2) merging:
+    int mbd = iwc.getMaxBufferedDocs();
+    if (mbd != -1 && mbd < lats.length/100) {
+      iwc.setMaxBufferedDocs(lats.length/100);
+    }
+    iwc.setCodec(getCodec());
+    Directory dir;
+    if (lats.length > 100000) {
+      dir = newFSDirectory(createTempDir("TestBKDTree"));
+    } else {
+      dir = getDirectory();
+    }
+    Set<Integer> deleted = new HashSet<>();
+    // RandomIndexWriter is too slow here:
+    IndexWriter w = new IndexWriter(dir, iwc);
+    for(int id=0;id<lats.length;id++) {
+      Document doc = new Document();
+      doc.add(newStringField("id", ""+id, Field.Store.NO));
+      doc.add(new NumericDocValuesField("id", id));
+      if (Double.isNaN(lats[id]) == false) {
+        doc.add(new Geo3DPoint("point", lats[id], lons[id]));
+      }
+      w.addDocument(doc);
+      if (id > 0 && random().nextInt(100) == 42) {
+        int idToDelete = random().nextInt(id);
+        w.deleteDocuments(new Term("id", ""+idToDelete));
+        deleted.add(idToDelete);
+        if (VERBOSE) {
+          System.err.println("  delete id=" + idToDelete);
+        }
+      }
+    }
+    if (random().nextBoolean()) {
+      w.forceMerge(1);
+    }
+    final IndexReader r = DirectoryReader.open(w);
+    w.close();
+
+    // We can't wrap with "exotic" readers because the geo3d query must see the Geo3DDVFormat:
+    IndexSearcher s = newSearcher(r, false);
+
+    int numThreads = TestUtil.nextInt(random(), 2, 5);
+
+    List<Thread> threads = new ArrayList<>();
+    final int iters = atLeast(100);
+
+    final CountDownLatch startingGun = new CountDownLatch(1);
+    final AtomicBoolean failed = new AtomicBoolean();
+
+    for(int i=0;i<numThreads;i++) {
+      Thread thread = new Thread() {
+          @Override
+          public void run() {
+            try {
+              _run();
+            } catch (Exception e) {
+              failed.set(true);
+              throw new RuntimeException(e);
+            }
+          }
+
+          private void _run() throws Exception {
+            startingGun.await();
+
+            NumericDocValues docIDToID = MultiDocValues.getNumericValues(r, "id");
+
+            for (int iter=0;iter<iters && failed.get() == false;iter++) {
+
+              GeoShape shape = randomShape(PlanetModel.WGS84);
+
+              if (VERBOSE) {
+                System.err.println("\n" + Thread.currentThread() + ": TEST: iter=" + iter + " shape="+shape);
+              }
+              
+              Query query = Geo3DPoint.newShapeQuery("point", shape);
+
+              if (VERBOSE) {
+                System.err.println("  using query: " + query);
+              }
+
+              final FixedBitSet hits = new FixedBitSet(r.maxDoc());
+
+              s.search(query, new SimpleCollector() {
+
+                  private int docBase;
+
+                  @Override
+                  public boolean needsScores() {
+                    return false;
+                  }
+
+                  @Override
+                  protected void doSetNextReader(LeafReaderContext context) throws IOException {
+                    docBase = context.docBase;
+                  }
+
+                  @Override
+                  public void collect(int doc) {
+                    hits.set(docBase+doc);
+                  }
+                });
+
+              if (VERBOSE) {
+                System.err.println("  hitCount: " + hits.cardinality());
+              }
+      
+              for(int docID=0;docID<r.maxDoc();docID++) {
+                int id = (int) docIDToID.get(docID);
+                if (Double.isNaN(lats[id]) == false) {
+
+                  // Accurate point:
+                  GeoPoint point1 = new GeoPoint(PlanetModel.WGS84, lats[id], lons[id]);
+
+                  // Quantized point (32 bits per dim):
+                  GeoPoint point2 = quantize(PlanetModel.WGS84.getMaximumMagnitude(), point1);
+
+                  if (shape.isWithin(point1) != shape.isWithin(point2)) {
+                    if (VERBOSE) {
+                      System.out.println("  skip checking docID=" + docID + " quantization changed the expected result from " + shape.isWithin(point1) + " to " + shape.isWithin(point2));
+                    }
+                    continue;
+                  }
+
+                  boolean expected = ((deleted.contains(id) == false) && shape.isWithin(point2));
+                  if (hits.get(docID) != expected) {
+                    fail(Thread.currentThread().getName() + ": iter=" + iter + " id=" + id + " docID=" + docID + " lat=" + lats[id] + " lon=" + lons[id] + " expected " + expected + " but got: " + hits.get(docID) + " deleted?=" + deleted.contains(id) + "\n  point1=" + point1 + ", iswithin="+shape.isWithin(point1)+"\n  point2=" + point2 + ", iswithin="+shape.isWithin(point2) + "\n  query=" + query);
+                  }
+                } else {
+                  assertFalse(hits.get(docID));
+                }
+
+              }
+            }
+          }
+        };
+      thread.setName("T" + i);
+      thread.start();
+      threads.add(thread);
+    }
+    startingGun.countDown();
+    for(Thread thread : threads) {
+      thread.join();
+    }
+    IOUtils.close(r, dir);
+  }
+
+  public void testToString() {
+    Geo3DPoint point = new Geo3DPoint("point", toRadians(44.244272), toRadians(7.769736));
+    assertEquals("Geo3DPoint <point: x=0.9248467864160119 y=0.06280434265368656 z=0.37682349005486243>", point.toString());
+  }
+
+  public void testShapeQueryToString() {
+    assertEquals("PointInGeo3DShapeQuery: field=point: Shape: GeoStandardCircle: {planetmodel=PlanetModel.WGS84, center=[lat=0.3861041107739683, lon=0.06780373760536706], radius=0.1(5.729577951308232)}",
+                 Geo3DPoint.newShapeQuery("point", GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84, toRadians(44.244272), toRadians(7.769736), 0.1)).toString());
+  }
+
+  private static Directory getDirectory() {     
+    return newDirectory();
+  }
+}


[07/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 0093e26)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoRectangle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoRectangle.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoRectangle.java
new file mode 100755
index 0000000..1420c11
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoRectangle.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.spatial3d.geom;
+
+/**
+ * Bounding box limited on four sides (top lat, bottom lat, left lon, right lon).
+ * The left-right maximum extent for this shape is PI; for anything larger, use
+ * GeoWideRectangle.
+ *
+ * @lucene.internal
+ */
+public class GeoRectangle extends GeoBaseBBox {
+  /** The top latitude of the rect */
+  protected final double topLat;
+  /** The bottom latitude of the rect */
+  protected final double bottomLat;
+  /** The left longitude of the rect */
+  protected final double leftLon;
+  /** The right longitude of the rect */
+  protected final double rightLon;
+  /** The cosine of a middle latitude */
+  protected final double cosMiddleLat;
+
+  /** The upper left hand corner point */
+  protected final GeoPoint ULHC;
+  /** The upper right hand corner point */
+  protected final GeoPoint URHC;
+  /** The lower right hand corner point */
+  protected final GeoPoint LRHC;
+  /** The lower left hand corner point */
+  protected final GeoPoint LLHC;
+
+  /** The top plane */
+  protected final SidedPlane topPlane;
+  /** The bottom plane */
+  protected final SidedPlane bottomPlane;
+  /** The left plane */
+  protected final SidedPlane leftPlane;
+  /** The right plane */
+  protected final SidedPlane rightPlane;
+
+  /** Notable points for the top plane */
+  protected final GeoPoint[] topPlanePoints;
+  /** Notable points for the bottom plane */
+  protected final GeoPoint[] bottomPlanePoints;
+  /** Notable points for the left plane */
+  protected final GeoPoint[] leftPlanePoints;
+  /** Notable points for the right plane */
+  protected final GeoPoint[] rightPlanePoints;
+
+  /** Center point */
+  protected final GeoPoint centerPoint;
+
+  /** Edge point for this rectangle */
+  protected final GeoPoint[] edgePoints;
+
+  /**
+   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
+   *@param planetModel is the planet model.
+   *@param topLat is the top latitude.
+   *@param bottomLat is the bottom latitude.
+   *@param leftLon is the left longitude.
+   *@param rightLon is the right longitude.
+   */
+  public GeoRectangle(final PlanetModel planetModel, final double topLat, final double bottomLat, final double leftLon, double rightLon) {
+    super(planetModel);
+    // Argument checking
+    if (topLat > Math.PI * 0.5 || topLat < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Top latitude out of range");
+    if (bottomLat > Math.PI * 0.5 || bottomLat < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Bottom latitude out of range");
+    if (topLat < bottomLat)
+      throw new IllegalArgumentException("Top latitude less than bottom latitude");
+    if (leftLon < -Math.PI || leftLon > Math.PI)
+      throw new IllegalArgumentException("Left longitude out of range");
+    if (rightLon < -Math.PI || rightLon > Math.PI)
+      throw new IllegalArgumentException("Right longitude out of range");
+    double extent = rightLon - leftLon;
+    if (extent < 0.0) {
+      extent += 2.0 * Math.PI;
+    }
+    if (extent > Math.PI)
+      throw new IllegalArgumentException("Width of rectangle too great");
+
+    this.topLat = topLat;
+    this.bottomLat = bottomLat;
+    this.leftLon = leftLon;
+    this.rightLon = rightLon;
+
+    final double sinTopLat = Math.sin(topLat);
+    final double cosTopLat = Math.cos(topLat);
+    final double sinBottomLat = Math.sin(bottomLat);
+    final double cosBottomLat = Math.cos(bottomLat);
+    final double sinLeftLon = Math.sin(leftLon);
+    final double cosLeftLon = Math.cos(leftLon);
+    final double sinRightLon = Math.sin(rightLon);
+    final double cosRightLon = Math.cos(rightLon);
+
+    // Now build the four points
+    this.ULHC = new GeoPoint(planetModel, sinTopLat, sinLeftLon, cosTopLat, cosLeftLon, topLat, leftLon);
+    this.URHC = new GeoPoint(planetModel, sinTopLat, sinRightLon, cosTopLat, cosRightLon, topLat, rightLon);
+    this.LRHC = new GeoPoint(planetModel, sinBottomLat, sinRightLon, cosBottomLat, cosRightLon, bottomLat, rightLon);
+    this.LLHC = new GeoPoint(planetModel, sinBottomLat, sinLeftLon, cosBottomLat, cosLeftLon, bottomLat, leftLon);
+
+    final double middleLat = (topLat + bottomLat) * 0.5;
+    final double sinMiddleLat = Math.sin(middleLat);
+    this.cosMiddleLat = Math.cos(middleLat);
+    // Normalize
+    while (leftLon > rightLon) {
+      rightLon += Math.PI * 2.0;
+    }
+    final double middleLon = (leftLon + rightLon) * 0.5;
+    final double sinMiddleLon = Math.sin(middleLon);
+    final double cosMiddleLon = Math.cos(middleLon);
+
+    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinMiddleLon, cosMiddleLat, cosMiddleLon);
+
+    this.topPlane = new SidedPlane(centerPoint, planetModel, sinTopLat);
+    this.bottomPlane = new SidedPlane(centerPoint, planetModel, sinBottomLat);
+    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
+    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
+
+    this.topPlanePoints = new GeoPoint[]{ULHC, URHC};
+    this.bottomPlanePoints = new GeoPoint[]{LLHC, LRHC};
+    this.leftPlanePoints = new GeoPoint[]{ULHC, LLHC};
+    this.rightPlanePoints = new GeoPoint[]{URHC, LRHC};
+
+    this.edgePoints = new GeoPoint[]{ULHC};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    final double newTopLat = topLat + angle;
+    final double newBottomLat = bottomLat - angle;
+    // Figuring out when we escalate to a special case requires some prefiguring
+    double currentLonSpan = rightLon - leftLon;
+    if (currentLonSpan < 0.0)
+      currentLonSpan += Math.PI * 2.0;
+    double newLeftLon = leftLon - angle;
+    double newRightLon = rightLon + angle;
+    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
+      newLeftLon = -Math.PI;
+      newRightLon = Math.PI;
+    }
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return topPlane.isWithin(x, y, z) &&
+        bottomPlane.isWithin(x, y, z) &&
+        leftPlane.isWithin(x, y, z) &&
+        rightPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public double getRadius() {
+    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
+    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
+    // the distance to the right or left edge from the center.
+    final double centerAngle = (rightLon - (rightLon + leftLon) * 0.5) * cosMiddleLat;
+    final double topAngle = centerPoint.arcDistance(URHC);
+    final double bottomAngle = centerPoint.arcDistance(LLHC);
+    return Math.max(centerAngle, Math.max(topAngle, bottomAngle));
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    return centerPoint;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return p.intersects(planetModel, topPlane, notablePoints, topPlanePoints, bounds, bottomPlane, leftPlane, rightPlane) ||
+        p.intersects(planetModel, bottomPlane, notablePoints, bottomPlanePoints, bounds, topPlane, leftPlane, rightPlane) ||
+        p.intersects(planetModel, leftPlane, notablePoints, leftPlanePoints, bounds, rightPlane, topPlane, bottomPlane) ||
+        p.intersects(planetModel, rightPlane, notablePoints, rightPlanePoints, bounds, leftPlane, topPlane, bottomPlane);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds.addHorizontalPlane(planetModel, topLat, topPlane, bottomPlane, leftPlane, rightPlane)
+      .addVerticalPlane(planetModel, rightLon, rightPlane, topPlane, bottomPlane, leftPlane)
+      .addHorizontalPlane(planetModel, bottomLat, bottomPlane, topPlane, leftPlane, rightPlane)
+      .addVerticalPlane(planetModel, leftLon, leftPlane, topPlane, bottomPlane, rightPlane)
+      .addPoint(ULHC).addPoint(URHC).addPoint(LLHC).addPoint(LRHC);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    //System.err.println(this+" getrelationship with "+path);
+    final int insideRectangle = isShapeInsideBBox(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some inside");
+      return OVERLAPS;
+    }
+
+    final boolean insideShape = path.isWithin(ULHC);
+
+    if (insideRectangle == ALL_INSIDE && insideShape) {
+      //System.err.println(" inside of each other");
+      return OVERLAPS;
+    }
+
+    if (path.intersects(topPlane, topPlanePoints, bottomPlane, leftPlane, rightPlane) ||
+        path.intersects(bottomPlane, bottomPlanePoints, topPlane, leftPlane, rightPlane) ||
+        path.intersects(leftPlane, leftPlanePoints, topPlane, bottomPlane, rightPlane) ||
+        path.intersects(rightPlane, rightPlanePoints, leftPlane, topPlane, bottomPlane)) {
+      //System.err.println(" edges intersect");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      //System.err.println(" shape inside rectangle");
+      return WITHIN;
+    }
+
+    if (insideShape) {
+      //System.err.println(" shape contains rectangle");
+      return CONTAINS;
+    }
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    final double topDistance = distanceStyle.computeDistance(planetModel, topPlane, x,y,z, bottomPlane, leftPlane, rightPlane);
+    final double bottomDistance = distanceStyle.computeDistance(planetModel, bottomPlane, x,y,z, topPlane, leftPlane, rightPlane);
+    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, rightPlane, topPlane, bottomPlane);
+    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, leftPlane, topPlane, bottomPlane);
+    
+    final double ULHCDistance = distanceStyle.computeDistance(ULHC, x,y,z);
+    final double URHCDistance = distanceStyle.computeDistance(URHC, x,y,z);
+    final double LRHCDistance = distanceStyle.computeDistance(LRHC, x,y,z);
+    final double LLHCDistance = distanceStyle.computeDistance(LLHC, x,y,z);
+    
+    return Math.min(
+      Math.min(
+        Math.min(topDistance, bottomDistance),
+        Math.min(leftDistance, rightDistance)),
+      Math.min(
+        Math.min(ULHCDistance, URHCDistance),
+        Math.min(LRHCDistance, LLHCDistance)));
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoRectangle))
+      return false;
+    GeoRectangle other = (GeoRectangle) o;
+    return super.equals(other) && other.ULHC.equals(ULHC) && other.LRHC.equals(LRHC);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result  + ULHC.hashCode();
+    result = 31 * result  + LRHC.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoRectangle: {planetmodel="+planetModel+", toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + "), bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
+  }
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoShape.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoShape.java
new file mode 100755
index 0000000..a2d3947
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoShape.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.spatial3d.geom;
+
+/**
+ * Generic shape.  This describes methods that help GeoAreas figure out
+ * how they interact with a shape, for the purposes of coming up with a
+ * set of geo hash values.
+ *
+ * @lucene.experimental
+ */
+public interface GeoShape extends Membership {
+
+  /**
+   * Return a sample point that is on the outside edge/boundary of the shape.
+   *
+   * @return samples of all edge points from distinct edge sections.  Typically one point
+   * is returned, but zero or two are also possible.
+   */
+  public GeoPoint[] getEdgePoints();
+
+  /**
+   * Assess whether a plane, within the provided bounds, intersects
+   * with the shape.  Note well that this method is allowed to return "true"
+   * if there are internal edges of a composite shape which intersect the plane.
+   * Doing this can cause getRelationship() for most GeoBBox shapes to return
+   * OVERLAPS rather than the more correct CONTAINS, but that cannot be
+   * helped for some complex shapes that are built out of overlapping parts.
+   *
+   * @param plane         is the plane to assess for intersection with the shape's edges or
+   *                      bounding curves.
+   * @param notablePoints represents the intersections of the plane with the supplied
+   *                      bounds.  These are used to disambiguate when two planes are identical and it needs
+   *                      to be determined whether any points exist that fulfill all the bounds.
+   * @param bounds        are a set of bounds that define an area that an
+   *                      intersection must be within in order to qualify (provided by a GeoArea).
+   * @return true if there's such an intersection, false if not.
+   */
+  public boolean intersects(final Plane plane, final GeoPoint[] notablePoints, final Membership... bounds);
+
+  /**
+   * Compute bounds for the shape.
+   *
+   * @param bounds is the input bounds object.
+   *             The input object will be modified.
+   */
+  public void getBounds(final Bounds bounds);
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoSizeable.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoSizeable.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoSizeable.java
new file mode 100755
index 0000000..3c7e2ef
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoSizeable.java
@@ -0,0 +1,40 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Some shapes can compute radii of a geocircle in which they are inscribed.
+ *
+ * @lucene.experimental
+ */
+public interface GeoSizeable {
+  /**
+   * Returns the radius of a circle into which the GeoSizeable area can
+   * be inscribed.
+   *
+   * @return the radius.
+   */
+  public double getRadius();
+
+  /**
+   * Returns the center of a circle into which the area will be inscribed.
+   *
+   * @return the center.
+   */
+  public GeoPoint getCenter();
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoSouthLatitudeZone.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoSouthLatitudeZone.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoSouthLatitudeZone.java
new file mode 100644
index 0000000..a1d8967
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoSouthLatitudeZone.java
@@ -0,0 +1,168 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * This GeoBBox represents an area rectangle limited only in north latitude.
+ *
+ * @lucene.internal
+ */
+public class GeoSouthLatitudeZone extends GeoBaseBBox {
+  /** The top latitude of the zone */
+  protected final double topLat;
+  /** The cosine of the top latitude of the zone */
+  protected final double cosTopLat;
+  /** The top plane of the zone */
+  protected final SidedPlane topPlane;
+  /** An interior point of the zone */
+  protected final GeoPoint interiorPoint;
+  /** Notable points for the plane (none) */
+  protected final static GeoPoint[] planePoints = new GeoPoint[0];
+  /** A point on the top boundary */
+  protected final GeoPoint topBoundaryPoint;
+  /** Edge points; a reference to the topBoundaryPoint */
+  protected final GeoPoint[] edgePoints;
+
+  /** Constructor.
+   *@param planetModel is the planet model.
+   *@param topLat is the top latitude of the zone.
+   */
+  public GeoSouthLatitudeZone(final PlanetModel planetModel, final double topLat) {
+    super(planetModel);
+    this.topLat = topLat;
+
+    final double sinTopLat = Math.sin(topLat);
+    this.cosTopLat = Math.cos(topLat);
+
+    // Compute an interior point.  Pick one whose lat is between top and bottom.
+    final double middleLat = (topLat - Math.PI * 0.5) * 0.5;
+    final double sinMiddleLat = Math.sin(middleLat);
+    this.interiorPoint = new GeoPoint(planetModel, sinMiddleLat, 0.0, Math.sqrt(1.0 - sinMiddleLat * sinMiddleLat), 1.0);
+    this.topBoundaryPoint = new GeoPoint(planetModel, sinTopLat, 0.0, Math.sqrt(1.0 - sinTopLat * sinTopLat), 1.0);
+
+    this.topPlane = new SidedPlane(interiorPoint, planetModel, sinTopLat);
+
+    this.edgePoints = new GeoPoint[]{topBoundaryPoint};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    final double newTopLat = topLat + angle;
+    final double newBottomLat = -Math.PI * 0.5;
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, -Math.PI, Math.PI);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return topPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public double getRadius() {
+    // This is a bit tricky.  I guess we should interpret this as meaning the angle of a circle that
+    // would contain all the bounding box points, when starting in the "center".
+    if (topLat > 0.0)
+      return Math.PI;
+    double maxCosLat = cosTopLat;
+    return maxCosLat * Math.PI;
+  }
+
+  /**
+   * Returns the center of a circle into which the area will be inscribed.
+   *
+   * @return the center.
+   */
+  @Override
+  public GeoPoint getCenter() {
+    return interiorPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return p.intersects(planetModel, topPlane, notablePoints, planePoints, bounds);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds
+      .addHorizontalPlane(planetModel, topLat, topPlane);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    final int insideRectangle = isShapeInsideBBox(path);
+    if (insideRectangle == SOME_INSIDE)
+      return OVERLAPS;
+
+    final boolean insideShape = path.isWithin(topBoundaryPoint);
+
+    if (insideRectangle == ALL_INSIDE && insideShape)
+      return OVERLAPS;
+
+    // Second, the shortcut of seeing whether endpoints are in/out is not going to
+    // work with no area endpoints.  So we rely entirely on intersections.
+
+    if (path.intersects(topPlane, planePoints))
+      return OVERLAPS;
+
+    // There is another case for latitude zones only.  This is when the boundaries of the shape all fit
+    // within the zone, but the shape includes areas outside the zone crossing a pole.
+    // In this case, the above "overlaps" check is insufficient.  We also need to check a point on either boundary
+    // whether it is within the shape.  If both such points are within, then CONTAINS is the right answer.  If
+    // one such point is within, then OVERLAPS is the right answer.
+
+    if (insideShape)
+      return CONTAINS;
+
+    if (insideRectangle == ALL_INSIDE)
+      return WITHIN;
+
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    return distanceStyle.computeDistance(planetModel, topPlane, x,y,z);
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoSouthLatitudeZone))
+      return false;
+    GeoSouthLatitudeZone other = (GeoSouthLatitudeZone) o;
+    return super.equals(other) && other.topBoundaryPoint.equals(topBoundaryPoint);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + topBoundaryPoint.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoSouthLatitudeZone: {planetmodel="+planetModel+", toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + ")}";
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoSouthRectangle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoSouthRectangle.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoSouthRectangle.java
new file mode 100644
index 0000000..806535e
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoSouthRectangle.java
@@ -0,0 +1,259 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Bounding box limited on three sides (top lat, left lon, right lon).  The
+ * other corner is the south pole.
+ * The left-right maximum extent for this shape is PI; for anything larger, use
+ * {@link GeoWideSouthRectangle}.
+ *
+ * @lucene.internal
+ */
+public class GeoSouthRectangle extends GeoBaseBBox {
+  /** The top latitude of the rect */
+  protected final double topLat;
+  /** The left longitude of the rect */
+  protected final double leftLon;
+  /** The right longitude of the rect */
+  protected final double rightLon;
+  /** The cosine of a middle latitude */
+  protected final double cosMiddleLat;
+  /** The upper left hand corner of the rectangle */
+  protected final GeoPoint ULHC;
+  /** The upper right hand corner of the rectangle */
+  protected final GeoPoint URHC;
+
+  /** The top plane */
+  protected final SidedPlane topPlane;
+  /** The left plane */
+  protected final SidedPlane leftPlane;
+  /** The right plane */
+  protected final SidedPlane rightPlane;
+
+  /** Notable points for the top plane */
+  protected final GeoPoint[] topPlanePoints;
+  /** Notable points for the left plane */
+  protected final GeoPoint[] leftPlanePoints;
+  /** Notable points for the right plane */
+  protected final GeoPoint[] rightPlanePoints;
+
+  /** The center point */
+  protected final GeoPoint centerPoint;
+
+  /** A point on the edge */
+  protected final GeoPoint[] edgePoints;
+
+  /**
+   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
+   *@param planetModel is the planet model.
+   *@param topLat is the top latitude.
+   *@param leftLon is the left longitude.
+   *@param rightLon is the right longitude.
+   */
+  public GeoSouthRectangle(final PlanetModel planetModel, final double topLat, final double leftLon, double rightLon) {
+    super(planetModel);
+    // Argument checking
+    if (topLat > Math.PI * 0.5 || topLat < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Top latitude out of range");
+    if (leftLon < -Math.PI || leftLon > Math.PI)
+      throw new IllegalArgumentException("Left longitude out of range");
+    if (rightLon < -Math.PI || rightLon > Math.PI)
+      throw new IllegalArgumentException("Right longitude out of range");
+    double extent = rightLon - leftLon;
+    if (extent < 0.0) {
+      extent += 2.0 * Math.PI;
+    }
+    if (extent > Math.PI)
+      throw new IllegalArgumentException("Width of rectangle too great");
+
+    this.topLat = topLat;
+    this.leftLon = leftLon;
+    this.rightLon = rightLon;
+
+    final double sinTopLat = Math.sin(topLat);
+    final double cosTopLat = Math.cos(topLat);
+    final double sinLeftLon = Math.sin(leftLon);
+    final double cosLeftLon = Math.cos(leftLon);
+    final double sinRightLon = Math.sin(rightLon);
+    final double cosRightLon = Math.cos(rightLon);
+
+    // Now build the four points
+    this.ULHC = new GeoPoint(planetModel, sinTopLat, sinLeftLon, cosTopLat, cosLeftLon, topLat, leftLon);
+    this.URHC = new GeoPoint(planetModel, sinTopLat, sinRightLon, cosTopLat, cosRightLon, topLat, rightLon);
+
+    final double middleLat = (topLat - Math.PI * 0.5) * 0.5;
+    final double sinMiddleLat = Math.sin(middleLat);
+    this.cosMiddleLat = Math.cos(middleLat);
+    // Normalize
+    while (leftLon > rightLon) {
+      rightLon += Math.PI * 2.0;
+    }
+    final double middleLon = (leftLon + rightLon) * 0.5;
+    final double sinMiddleLon = Math.sin(middleLon);
+    final double cosMiddleLon = Math.cos(middleLon);
+
+    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinMiddleLon, cosMiddleLat, cosMiddleLon);
+
+    this.topPlane = new SidedPlane(centerPoint, planetModel, sinTopLat);
+    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
+    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
+
+    this.topPlanePoints = new GeoPoint[]{ULHC, URHC};
+    this.leftPlanePoints = new GeoPoint[]{ULHC, planetModel.SOUTH_POLE};
+    this.rightPlanePoints = new GeoPoint[]{URHC, planetModel.SOUTH_POLE};
+    
+    this.edgePoints = new GeoPoint[]{planetModel.SOUTH_POLE};
+
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    final double newTopLat = topLat + angle;
+    final double newBottomLat = -Math.PI * 0.5;
+    // Figuring out when we escalate to a special case requires some prefiguring
+    double currentLonSpan = rightLon - leftLon;
+    if (currentLonSpan < 0.0)
+      currentLonSpan += Math.PI * 2.0;
+    double newLeftLon = leftLon - angle;
+    double newRightLon = rightLon + angle;
+    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
+      newLeftLon = -Math.PI;
+      newRightLon = Math.PI;
+    }
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return topPlane.isWithin(x, y, z) &&
+        leftPlane.isWithin(x, y, z) &&
+        rightPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public double getRadius() {
+    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
+    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
+    // the distance to the right or left edge from the center.
+    final double centerAngle = (rightLon - (rightLon + leftLon) * 0.5) * cosMiddleLat;
+    final double topAngle = centerPoint.arcDistance(URHC);
+    return Math.max(centerAngle, topAngle);
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    return centerPoint;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return p.intersects(planetModel, topPlane, notablePoints, topPlanePoints, bounds, leftPlane, rightPlane) ||
+        p.intersects(planetModel, leftPlane, notablePoints, leftPlanePoints, bounds, rightPlane, topPlane) ||
+        p.intersects(planetModel, rightPlane, notablePoints, rightPlanePoints, bounds, leftPlane, topPlane);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds
+      .addHorizontalPlane(planetModel, topLat, topPlane, leftPlane, rightPlane)
+      .addVerticalPlane(planetModel, leftLon, leftPlane, topPlane, rightPlane)
+      .addVerticalPlane(planetModel, rightLon, rightPlane, topPlane, leftPlane)
+      .addPoint(URHC).addPoint(ULHC).addPoint(planetModel.SOUTH_POLE);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    //System.err.println(this+" getrelationship with "+path);
+    final int insideRectangle = isShapeInsideBBox(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some inside");
+      return OVERLAPS;
+    }
+
+    final boolean insideShape = path.isWithin(planetModel.SOUTH_POLE);
+
+    if (insideRectangle == ALL_INSIDE && insideShape) {
+      //System.err.println(" inside of each other");
+      return OVERLAPS;
+    }
+
+    if (path.intersects(topPlane, topPlanePoints, leftPlane, rightPlane) ||
+        path.intersects(leftPlane, leftPlanePoints, topPlane, rightPlane) ||
+        path.intersects(rightPlane, rightPlanePoints, leftPlane, topPlane)) {
+      //System.err.println(" edges intersect");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      //System.err.println(" shape inside rectangle");
+      return WITHIN;
+    }
+
+    if (insideShape) {
+      //System.err.println(" shape contains rectangle");
+      return CONTAINS;
+    }
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    final double topDistance = distanceStyle.computeDistance(planetModel, topPlane, x,y,z, leftPlane, rightPlane);
+    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, rightPlane, topPlane);
+    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, leftPlane, topPlane);
+    
+    final double ULHCDistance = distanceStyle.computeDistance(ULHC, x,y,z);
+    final double URHCDistance = distanceStyle.computeDistance(URHC, x,y,z);
+    
+    return Math.min(
+      Math.min(
+        topDistance,
+        Math.min(leftDistance, rightDistance)),
+      Math.min(ULHCDistance, URHCDistance));
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoSouthRectangle))
+      return false;
+    GeoSouthRectangle other = (GeoSouthRectangle) o;
+    return super.equals(other) && other.ULHC.equals(ULHC) && other.URHC.equals(URHC);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + ULHC.hashCode();
+    result = 31 * result + URHC.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoSouthRectangle: {planetmodel="+planetModel+", toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
+  }
+}
+  
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoStandardCircle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoStandardCircle.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoStandardCircle.java
new file mode 100755
index 0000000..bbf5046
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoStandardCircle.java
@@ -0,0 +1,168 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Circular area with a center and radius.
+ *
+ * @lucene.experimental
+ */
+public class GeoStandardCircle extends GeoBaseCircle {
+  /** Center of circle */
+  protected final GeoPoint center;
+  /** Cutoff angle of circle (not quite the same thing as radius) */
+  protected final double cutoffAngle;
+  /** The plane describing the circle (really an ellipse on a non-spherical world) */
+  protected final SidedPlane circlePlane;
+  /** A point that is on the world and on the circle plane */
+  protected final GeoPoint[] edgePoints;
+  /** Notable points for a circle -- there aren't any */
+  protected static final GeoPoint[] circlePoints = new GeoPoint[0];
+
+  /** Constructor.
+   *@param planetModel is the planet model.
+   *@param lat is the center latitude.
+   *@param lon is the center longitude.
+   *@param cutoffAngle is the cutoff angle for the circle.
+   */
+  public GeoStandardCircle(final PlanetModel planetModel, final double lat, final double lon, final double cutoffAngle) {
+    super(planetModel);
+    if (lat < -Math.PI * 0.5 || lat > Math.PI * 0.5)
+      throw new IllegalArgumentException("Latitude out of bounds");
+    if (lon < -Math.PI || lon > Math.PI)
+      throw new IllegalArgumentException("Longitude out of bounds");
+    if (cutoffAngle < 0.0 || cutoffAngle > Math.PI)
+      throw new IllegalArgumentException("Cutoff angle out of bounds");
+    if (cutoffAngle < Vector.MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("Cutoff angle cannot be effectively zero");
+    this.center = new GeoPoint(planetModel, lat, lon);
+    // In an ellipsoidal world, cutoff distances make no sense, unfortunately.  Only membership
+    // can be used to make in/out determination.
+    this.cutoffAngle = cutoffAngle;
+    // Compute two points on the circle, with the right angle from the center.  We'll use these
+    // to obtain the perpendicular plane to the circle.
+    double upperLat = lat + cutoffAngle;
+    double upperLon = lon;
+    if (upperLat > Math.PI * 0.5) {
+      upperLon += Math.PI;
+      if (upperLon > Math.PI)
+        upperLon -= 2.0 * Math.PI;
+      upperLat = Math.PI - upperLat;
+    }
+    double lowerLat = lat - cutoffAngle;
+    double lowerLon = lon;
+    if (lowerLat < -Math.PI * 0.5) {
+      lowerLon += Math.PI;
+      if (lowerLon > Math.PI)
+        lowerLon -= 2.0 * Math.PI;
+      lowerLat = -Math.PI - lowerLat;
+    }
+    final GeoPoint upperPoint = new GeoPoint(planetModel, upperLat, upperLon);
+    final GeoPoint lowerPoint = new GeoPoint(planetModel, lowerLat, lowerLon);
+    if (Math.abs(cutoffAngle - Math.PI) < Vector.MINIMUM_RESOLUTION) {
+      // Circle is the whole world
+      this.circlePlane = null;
+      this.edgePoints = new GeoPoint[0];
+    } else {
+      // Construct normal plane
+      final Plane normalPlane = Plane.constructNormalizedZPlane(upperPoint, lowerPoint, center);
+      // Construct a sided plane that goes through the two points and whose normal is in the normalPlane.
+      this.circlePlane = SidedPlane.constructNormalizedPerpendicularSidedPlane(center, normalPlane, upperPoint, lowerPoint);
+      if (circlePlane == null)
+        throw new IllegalArgumentException("Couldn't construct circle plane, probably too small?  Cutoff angle = "+cutoffAngle+"; upperPoint = "+upperPoint+"; lowerPoint = "+lowerPoint);
+      final GeoPoint recomputedIntersectionPoint = circlePlane.getSampleIntersectionPoint(planetModel, normalPlane);
+      if (recomputedIntersectionPoint == null)
+        throw new IllegalArgumentException("Couldn't construct intersection point, probably circle too small?  Plane = "+circlePlane);
+      this.edgePoints = new GeoPoint[]{recomputedIntersectionPoint};
+    }
+  }
+
+  @Override
+  public double getRadius() {
+    return cutoffAngle;
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    return center;
+  }
+
+  @Override
+  protected double distance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    return distanceStyle.computeDistance(this.center, x, y, z);
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    return distanceStyle.computeDistance(planetModel, circlePlane, x, y, z);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    if (circlePlane == null) {
+      return true;
+    }
+    // Fastest way of determining membership
+    return circlePlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    if (circlePlane == null) {
+      return false;
+    }
+    return circlePlane.intersects(planetModel, p, notablePoints, circlePoints, bounds);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    if (circlePlane == null) {
+      // Entire world; should already be covered
+      return;
+    }
+    bounds.addPoint(center);
+    bounds.addPlane(planetModel, circlePlane);
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoStandardCircle))
+      return false;
+    GeoStandardCircle other = (GeoStandardCircle) o;
+    return super.equals(other) && other.center.equals(center) && other.cutoffAngle == cutoffAngle;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + center.hashCode();
+    long temp = Double.doubleToLongBits(cutoffAngle);
+    result = 31 * result + (int) (temp ^ (temp >>> 32));
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoStandardCircle: {planetmodel=" + planetModel+", center=" + center + ", radius=" + cutoffAngle + "(" + cutoffAngle * 180.0 / Math.PI + ")}";
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideDegenerateHorizontalLine.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideDegenerateHorizontalLine.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideDegenerateHorizontalLine.java
new file mode 100644
index 0000000..48a73af
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideDegenerateHorizontalLine.java
@@ -0,0 +1,238 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Degenerate bounding box wider than PI and limited on two sides (left lon, right lon).
+ *
+ * @lucene.internal
+ */
+public class GeoWideDegenerateHorizontalLine extends GeoBaseBBox {
+  /** The latitude of the line */
+  protected final double latitude;
+  /** The left longitude cutoff of the line */
+  protected final double leftLon;
+  /** The right longitude cutoff of the line */
+  protected final double rightLon;
+
+  /** The left end of the line */
+  protected final GeoPoint LHC;
+  /** The right end of the line */
+  protected final GeoPoint RHC;
+
+  /** The plane the line is in */
+  protected final Plane plane;
+  /** The left cutoff plane */
+  protected final SidedPlane leftPlane;
+  /** The right cutoff plane */
+  protected final SidedPlane rightPlane;
+
+  /** Notable points for the line */
+  protected final GeoPoint[] planePoints;
+
+  /** Center point for the line */
+  protected final GeoPoint centerPoint;
+
+  /** Left/right combination bound */
+  protected final EitherBound eitherBound;
+
+  /** A point on the line */
+  protected final GeoPoint[] edgePoints;
+
+  /**
+   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}.
+   * Horizontal angle must be greater than or equal to PI.
+   *@param planetModel is the planet model.
+   *@param latitude is the line latitude.
+   *@param leftLon is the left cutoff longitude.
+   *@param rightLon is the right cutoff longitude.
+   */
+  public GeoWideDegenerateHorizontalLine(final PlanetModel planetModel, final double latitude, final double leftLon, double rightLon) {
+    super(planetModel);
+    // Argument checking
+    if (latitude > Math.PI * 0.5 || latitude < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Latitude out of range");
+    if (leftLon < -Math.PI || leftLon > Math.PI)
+      throw new IllegalArgumentException("Left longitude out of range");
+    if (rightLon < -Math.PI || rightLon > Math.PI)
+      throw new IllegalArgumentException("Right longitude out of range");
+    double extent = rightLon - leftLon;
+    if (extent < 0.0) {
+      extent += 2.0 * Math.PI;
+    }
+    if (extent < Math.PI)
+      throw new IllegalArgumentException("Width of rectangle too small");
+
+    this.latitude = latitude;
+    this.leftLon = leftLon;
+    this.rightLon = rightLon;
+
+    final double sinLatitude = Math.sin(latitude);
+    final double cosLatitude = Math.cos(latitude);
+    final double sinLeftLon = Math.sin(leftLon);
+    final double cosLeftLon = Math.cos(leftLon);
+    final double sinRightLon = Math.sin(rightLon);
+    final double cosRightLon = Math.cos(rightLon);
+
+    // Now build the two points
+    this.LHC = new GeoPoint(planetModel, sinLatitude, sinLeftLon, cosLatitude, cosLeftLon, latitude, leftLon);
+    this.RHC = new GeoPoint(planetModel, sinLatitude, sinRightLon, cosLatitude, cosRightLon, latitude, rightLon);
+
+    this.plane = new Plane(planetModel, sinLatitude);
+
+    // Normalize
+    while (leftLon > rightLon) {
+      rightLon += Math.PI * 2.0;
+    }
+    double middleLon = (leftLon + rightLon) * 0.5;
+    double sinMiddleLon = Math.sin(middleLon);
+    double cosMiddleLon = Math.cos(middleLon);
+
+    this.centerPoint = new GeoPoint(planetModel, sinLatitude, sinMiddleLon, cosLatitude, cosMiddleLon);
+
+    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
+    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
+
+    this.planePoints = new GeoPoint[]{LHC, RHC};
+
+    this.eitherBound = new EitherBound();
+
+    this.edgePoints = new GeoPoint[]{centerPoint};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    final double newTopLat = latitude + angle;
+    final double newBottomLat = latitude - angle;
+    // Figuring out when we escalate to a special case requires some prefiguring
+    double currentLonSpan = rightLon - leftLon;
+    if (currentLonSpan < 0.0)
+      currentLonSpan += Math.PI * 2.0;
+    double newLeftLon = leftLon - angle;
+    double newRightLon = rightLon + angle;
+    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
+      newLeftLon = -Math.PI;
+      newRightLon = Math.PI;
+    }
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return plane.evaluateIsZero(x, y, z) &&
+        (leftPlane.isWithin(x, y, z) ||
+            rightPlane.isWithin(x, y, z));
+  }
+
+  @Override
+  public double getRadius() {
+    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
+    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
+    // the distance to the right or left edge from the center.
+    final double topAngle = centerPoint.arcDistance(RHC);
+    final double bottomAngle = centerPoint.arcDistance(LHC);
+    return Math.max(topAngle, bottomAngle);
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    return centerPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    // Right and left bounds are essentially independent hemispheres; crossing into the wrong part of one
+    // requires crossing into the right part of the other.  So intersection can ignore the left/right bounds.
+    return p.intersects(planetModel, plane, notablePoints, planePoints, bounds, eitherBound);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds.isWide()
+      .addHorizontalPlane(planetModel, latitude, plane, eitherBound)
+      .addPoint(LHC)
+      .addPoint(RHC);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    if (path.intersects(plane, planePoints, eitherBound)) {
+      return OVERLAPS;
+    }
+
+    if (path.isWithin(centerPoint)) {
+      return CONTAINS;
+    }
+
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    final double distance = distanceStyle.computeDistance(planetModel, plane, x,y,z, eitherBound);
+    
+    final double LHCDistance = distanceStyle.computeDistance(LHC, x,y,z);
+    final double RHCDistance = distanceStyle.computeDistance(RHC, x,y,z);
+    
+    return Math.min(
+      distance,
+      Math.min(LHCDistance, RHCDistance));
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoWideDegenerateHorizontalLine))
+      return false;
+    GeoWideDegenerateHorizontalLine other = (GeoWideDegenerateHorizontalLine) o;
+    return super.equals(other) && other.LHC.equals(LHC) && other.RHC.equals(RHC);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + LHC.hashCode();
+    result = 31 * result + RHC.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoWideDegenerateHorizontalLine: {planetmodel="+planetModel+", latitude=" + latitude + "(" + latitude * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightLon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
+  }
+
+  /** Membership implementation representing a wide cutoff (more than 180 degrees).
+   */
+  protected class EitherBound implements Membership {
+    /** Constructor.
+     */
+    public EitherBound() {
+    }
+
+    @Override
+    public boolean isWithin(final double x, final double y, final double z) {
+      return leftPlane.isWithin(x, y, z) || rightPlane.isWithin(x, y, z);
+    }
+  }
+}
+  
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideLongitudeSlice.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideLongitudeSlice.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideLongitudeSlice.java
new file mode 100755
index 0000000..1d61876
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideLongitudeSlice.java
@@ -0,0 +1,208 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Bounding box wider than PI but limited on left and right sides (
+ * left lon, right lon).
+ *
+ * @lucene.internal
+ */
+public class GeoWideLongitudeSlice extends GeoBaseBBox {
+  /** The left longitude */
+  protected final double leftLon;
+  /** The right longitude */
+  protected final double rightLon;
+
+  /** The left plane */
+  protected final SidedPlane leftPlane;
+  /** The right plane */
+  protected final SidedPlane rightPlane;
+
+  /** Notable points for the shape */
+  protected final GeoPoint[] planePoints;
+
+  /** Center point for the shape */
+  protected final GeoPoint centerPoint;
+
+  /** A point on the edge of the shape */
+  protected final GeoPoint[] edgePoints; 
+
+  /**
+   * Accepts only values in the following ranges: lon: {@code -PI -> PI}.
+   * Horizantal angle must be greater than or equal to PI.
+   *@param planetModel is the planet model.
+   *@param leftLon is the left longitude.
+   *@param rightLon is the right longitude.
+   */
+  public GeoWideLongitudeSlice(final PlanetModel planetModel, final double leftLon, double rightLon) {
+    super(planetModel);
+    // Argument checking
+    if (leftLon < -Math.PI || leftLon > Math.PI)
+      throw new IllegalArgumentException("Left longitude out of range");
+    if (rightLon < -Math.PI || rightLon > Math.PI)
+      throw new IllegalArgumentException("Right longitude out of range");
+    double extent = rightLon - leftLon;
+    if (extent < 0.0) {
+      extent += 2.0 * Math.PI;
+    }
+    if (extent < Math.PI)
+      throw new IllegalArgumentException("Width of rectangle too small");
+
+    this.leftLon = leftLon;
+    this.rightLon = rightLon;
+
+    final double sinLeftLon = Math.sin(leftLon);
+    final double cosLeftLon = Math.cos(leftLon);
+    final double sinRightLon = Math.sin(rightLon);
+    final double cosRightLon = Math.cos(rightLon);
+
+    // Normalize
+    while (leftLon > rightLon) {
+      rightLon += Math.PI * 2.0;
+    }
+    final double middleLon = (leftLon + rightLon) * 0.5;
+    this.centerPoint = new GeoPoint(planetModel, 0.0, middleLon);
+
+    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
+    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
+    
+    this.planePoints = new GeoPoint[]{planetModel.NORTH_POLE, planetModel.SOUTH_POLE};
+    this.edgePoints = new GeoPoint[]{planetModel.NORTH_POLE};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    // Figuring out when we escalate to a special case requires some prefiguring
+    double currentLonSpan = rightLon - leftLon;
+    if (currentLonSpan < 0.0)
+      currentLonSpan += Math.PI * 2.0;
+    double newLeftLon = leftLon - angle;
+    double newRightLon = rightLon + angle;
+    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
+      newLeftLon = -Math.PI;
+      newRightLon = Math.PI;
+    }
+    return GeoBBoxFactory.makeGeoBBox(planetModel, Math.PI * 0.5, -Math.PI * 0.5, newLeftLon, newRightLon);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return leftPlane.isWithin(x, y, z) ||
+        rightPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public double getRadius() {
+    // Compute the extent and divide by two
+    double extent = rightLon - leftLon;
+    if (extent < 0.0)
+      extent += Math.PI * 2.0;
+    return Math.max(Math.PI * 0.5, extent * 0.5);
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    return centerPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    // Right and left bounds are essentially independent hemispheres; crossing into the wrong part of one
+    // requires crossing into the right part of the other.  So intersection can ignore the left/right bounds.
+    return p.intersects(planetModel, leftPlane, notablePoints, planePoints, bounds) ||
+        p.intersects(planetModel, rightPlane, notablePoints, planePoints, bounds);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds.isWide()
+      .addVerticalPlane(planetModel, leftLon, leftPlane)
+      .addVerticalPlane(planetModel, rightLon, rightPlane)
+      .addPoint(planetModel.NORTH_POLE)
+      .addPoint(planetModel.SOUTH_POLE);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    final int insideRectangle = isShapeInsideBBox(path);
+    if (insideRectangle == SOME_INSIDE)
+      return OVERLAPS;
+
+    final boolean insideShape = path.isWithin(planetModel.NORTH_POLE);
+
+    if (insideRectangle == ALL_INSIDE && insideShape)
+      return OVERLAPS;
+
+    if (path.intersects(leftPlane, planePoints) ||
+        path.intersects(rightPlane, planePoints))
+      return OVERLAPS;
+
+    if (insideRectangle == ALL_INSIDE)
+      return WITHIN;
+
+    if (insideShape)
+      return CONTAINS;
+
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    // Because the rectangle exceeds 180 degrees, it is safe to compute the horizontally 
+    // unbounded distance to both the left and the right and only take the minimum of the two.
+    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z);
+    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z);
+    
+    final double northDistance = distanceStyle.computeDistance(planetModel.NORTH_POLE, x,y,z);
+    final double southDistance = distanceStyle.computeDistance(planetModel.SOUTH_POLE, x,y,z);
+    
+    return Math.min(
+      Math.min(leftDistance, rightDistance),
+      Math.min(northDistance, southDistance));
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoWideLongitudeSlice))
+      return false;
+    GeoWideLongitudeSlice other = (GeoWideLongitudeSlice) o;
+    return super.equals(other) && other.leftLon == leftLon && other.rightLon == rightLon;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    long temp = Double.doubleToLongBits(leftLon);
+    result = 31 * result + (int) (temp ^ (temp >>> 32));
+    temp = Double.doubleToLongBits(rightLon);
+    result = 31 * result + (int) (temp ^ (temp >>> 32));
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoWideLongitudeSlice: {planetmodel="+planetModel+", leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
+  }
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideNorthRectangle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideNorthRectangle.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideNorthRectangle.java
new file mode 100644
index 0000000..9f9dd49
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideNorthRectangle.java
@@ -0,0 +1,286 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Bounding box wider than PI but limited on three sides (
+ * bottom lat, left lon, right lon).
+ *
+ * @lucene.internal
+ */
+public class GeoWideNorthRectangle extends GeoBaseBBox {
+  /** Bottom latitude */
+  protected final double bottomLat;
+  /** Left longitude */
+  protected final double leftLon;
+  /** Right longitude */
+  protected final double rightLon;
+
+  /** The cosine of the middle latitude */
+  protected final double cosMiddleLat;
+
+  /** The lower right hand corner point */
+  protected final GeoPoint LRHC;
+  /** The lower left hand corner point */
+  protected final GeoPoint LLHC;
+
+  /** The bottom plane */
+  protected final SidedPlane bottomPlane;
+  /** The left plane */
+  protected final SidedPlane leftPlane;
+  /** The right plane */
+  protected final SidedPlane rightPlane;
+
+  /** Notable points for the bottom plane */
+  protected final GeoPoint[] bottomPlanePoints;
+  /** Notable points for the left plane */
+  protected final GeoPoint[] leftPlanePoints;
+  /** Notable points for the right plane */
+  protected final GeoPoint[] rightPlanePoints;
+
+  /** Center point */
+  protected final GeoPoint centerPoint;
+
+  /** Composite left/right bounds */
+  protected final EitherBound eitherBound;
+
+  /** A point on the edge */
+  protected final GeoPoint[] edgePoints;
+
+  /**
+   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}.
+   * Horizontal angle must be greater than or equal to PI.
+   */
+  public GeoWideNorthRectangle(final PlanetModel planetModel, final double bottomLat, final double leftLon, double rightLon) {
+    super(planetModel);
+    // Argument checking
+    if (bottomLat > Math.PI * 0.5 || bottomLat < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Bottom latitude out of range");
+    if (leftLon < -Math.PI || leftLon > Math.PI)
+      throw new IllegalArgumentException("Left longitude out of range");
+    if (rightLon < -Math.PI || rightLon > Math.PI)
+      throw new IllegalArgumentException("Right longitude out of range");
+    double extent = rightLon - leftLon;
+    if (extent < 0.0) {
+      extent += 2.0 * Math.PI;
+    }
+    if (extent < Math.PI)
+      throw new IllegalArgumentException("Width of rectangle too small");
+
+    this.bottomLat = bottomLat;
+    this.leftLon = leftLon;
+    this.rightLon = rightLon;
+
+    final double sinBottomLat = Math.sin(bottomLat);
+    final double cosBottomLat = Math.cos(bottomLat);
+    final double sinLeftLon = Math.sin(leftLon);
+    final double cosLeftLon = Math.cos(leftLon);
+    final double sinRightLon = Math.sin(rightLon);
+    final double cosRightLon = Math.cos(rightLon);
+
+    // Now build the four points
+    this.LRHC = new GeoPoint(planetModel, sinBottomLat, sinRightLon, cosBottomLat, cosRightLon, bottomLat, rightLon);
+    this.LLHC = new GeoPoint(planetModel, sinBottomLat, sinLeftLon, cosBottomLat, cosLeftLon, bottomLat, leftLon);
+
+    final double middleLat = (Math.PI * 0.5 + bottomLat) * 0.5;
+    final double sinMiddleLat = Math.sin(middleLat);
+    this.cosMiddleLat = Math.cos(middleLat);
+    // Normalize
+    while (leftLon > rightLon) {
+      rightLon += Math.PI * 2.0;
+    }
+    final double middleLon = (leftLon + rightLon) * 0.5;
+    final double sinMiddleLon = Math.sin(middleLon);
+    final double cosMiddleLon = Math.cos(middleLon);
+
+    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinMiddleLon, cosMiddleLat, cosMiddleLon);
+
+    this.bottomPlane = new SidedPlane(centerPoint, planetModel, sinBottomLat);
+    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
+    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
+
+    this.bottomPlanePoints = new GeoPoint[]{LLHC, LRHC};
+    this.leftPlanePoints = new GeoPoint[]{planetModel.NORTH_POLE, LLHC};
+    this.rightPlanePoints = new GeoPoint[]{planetModel.NORTH_POLE, LRHC};
+
+    this.eitherBound = new EitherBound();
+    this.edgePoints = new GeoPoint[]{planetModel.NORTH_POLE};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    final double newTopLat = Math.PI * 0.5;
+    final double newBottomLat = bottomLat - angle;
+    // Figuring out when we escalate to a special case requires some prefiguring
+    double currentLonSpan = rightLon - leftLon;
+    if (currentLonSpan < 0.0)
+      currentLonSpan += Math.PI * 2.0;
+    double newLeftLon = leftLon - angle;
+    double newRightLon = rightLon + angle;
+    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
+      newLeftLon = -Math.PI;
+      newRightLon = Math.PI;
+    }
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return
+        bottomPlane.isWithin(x, y, z) &&
+            (leftPlane.isWithin(x, y, z) ||
+                rightPlane.isWithin(x, y, z));
+  }
+
+  @Override
+  public double getRadius() {
+    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
+    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
+    // the distance to the right or left edge from the center.
+    final double centerAngle = (rightLon - (rightLon + leftLon) * 0.5) * cosMiddleLat;
+    final double bottomAngle = centerPoint.arcDistance(LLHC);
+    return Math.max(centerAngle, bottomAngle);
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    return centerPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    // Right and left bounds are essentially independent hemispheres; crossing into the wrong part of one
+    // requires crossing into the right part of the other.  So intersection can ignore the left/right bounds.
+    return
+        p.intersects(planetModel, bottomPlane, notablePoints, bottomPlanePoints, bounds, eitherBound) ||
+            p.intersects(planetModel, leftPlane, notablePoints, leftPlanePoints, bounds, bottomPlane) ||
+            p.intersects(planetModel, rightPlane, notablePoints, rightPlanePoints, bounds, bottomPlane);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds.isWide()
+      .addHorizontalPlane(planetModel, bottomLat, bottomPlane, eitherBound)
+      .addVerticalPlane(planetModel, leftLon, leftPlane, bottomPlane)
+      .addVerticalPlane(planetModel, rightLon, rightPlane, bottomPlane)
+      .addPoint(LLHC).addPoint(LRHC).addPoint(planetModel.NORTH_POLE);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    //System.err.println(this+" comparing to "+path);
+    final int insideRectangle = isShapeInsideBBox(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some inside");
+      return OVERLAPS;
+    }
+
+    final boolean insideShape = path.isWithin(planetModel.NORTH_POLE);
+
+    if (insideRectangle == ALL_INSIDE && insideShape) {
+      //System.err.println(" both inside each other");
+      return OVERLAPS;
+    }
+
+    if (
+        path.intersects(bottomPlane, bottomPlanePoints, eitherBound) ||
+            path.intersects(leftPlane, leftPlanePoints, bottomPlane) ||
+            path.intersects(rightPlane, rightPlanePoints, bottomPlane)) {
+      //System.err.println(" edges intersect");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      //System.err.println(" shape inside rectangle");
+      return WITHIN;
+    }
+
+    if (insideShape) {
+      //System.err.println(" rectangle inside shape");
+      return CONTAINS;
+    }
+
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    final double bottomDistance = distanceStyle.computeDistance(planetModel, bottomPlane, x,y,z, eitherBound);
+    // Because the rectangle exceeds 180 degrees, it is safe to compute the horizontally 
+    // unbounded distance to both the left and the right and only take the minimum of the two.
+    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, bottomPlane);
+    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, bottomPlane);
+    
+    final double LRHCDistance = distanceStyle.computeDistance(LRHC, x,y,z);
+    final double LLHCDistance = distanceStyle.computeDistance(LLHC, x,y,z);
+    
+    return Math.min(
+      Math.min(
+        bottomDistance,
+        Math.min(leftDistance, rightDistance)),
+      Math.min(LRHCDistance, LLHCDistance));
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoWideNorthRectangle))
+      return false;
+    GeoWideNorthRectangle other = (GeoWideNorthRectangle) o;
+    return super.equals(other) && other.LLHC.equals(LLHC) && other.LRHC.equals(LRHC);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + LLHC.hashCode();
+    result = 31 * result + LRHC.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoWideNorthRectangle: {planetmodel="+planetModel+", bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
+  }
+
+  /** Membership implementation representing a wide (more than 180 degree) bound.
+   */
+  protected class EitherBound implements Membership {
+    /** Constructor.
+     */
+    public EitherBound() {
+    }
+
+    @Override
+    public boolean isWithin(final Vector v) {
+      return leftPlane.isWithin(v) || rightPlane.isWithin(v);
+    }
+
+    @Override
+    public boolean isWithin(final double x, final double y, final double z) {
+      return leftPlane.isWithin(x, y, z) || rightPlane.isWithin(x, y, z);
+    }
+  }
+}
+  
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideRectangle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideRectangle.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideRectangle.java
new file mode 100755
index 0000000..c561747
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideRectangle.java
@@ -0,0 +1,319 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Bounding box wider than PI but limited on four sides (top lat,
+ * bottom lat, left lon, right lon).
+ *
+ * @lucene.internal
+ */
+public class GeoWideRectangle extends GeoBaseBBox {
+  /** The top latitude */
+  protected final double topLat;
+  /** The bottom latitude */
+  protected final double bottomLat;
+  /** The left longitude */
+  protected final double leftLon;
+  /** The right longitude */
+  protected final double rightLon;
+
+  /** Cosine of the middle latitude */
+  protected final double cosMiddleLat;
+
+  /** Upper left hand corner point */
+  protected final GeoPoint ULHC;
+  /** Lower right hand corner point */
+  protected final GeoPoint URHC;
+  /** Lower right hand corner point */
+  protected final GeoPoint LRHC;
+  /** Lower left hand corner point */
+  protected final GeoPoint LLHC;
+
+  /** Top plane */
+  protected final SidedPlane topPlane;
+  /** Bottom plane */
+  protected final SidedPlane bottomPlane;
+  /** Left plane */
+  protected final SidedPlane leftPlane;
+  /** Right plane */
+  protected final SidedPlane rightPlane;
+
+  /** Top plane's notable points */
+  protected final GeoPoint[] topPlanePoints;
+  /** Bottom plane's notable points */
+  protected final GeoPoint[] bottomPlanePoints;
+  /** Left plane's notable points */
+  protected final GeoPoint[] leftPlanePoints;
+  /** Right plane's notable points */
+  protected final GeoPoint[] rightPlanePoints;
+
+  /** Center point */
+  protected final GeoPoint centerPoint;
+
+  /** Combined left/right bounds */
+  protected final EitherBound eitherBound;
+
+  /** A point on the edge */
+  protected final GeoPoint[] edgePoints;
+
+  /**
+   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}.
+   * Horizontal angle must be greater than or equal to PI.
+   */
+  public GeoWideRectangle(final PlanetModel planetModel, final double topLat, final double bottomLat, final double leftLon, double rightLon) {
+    super(planetModel);
+    // Argument checking
+    if (topLat > Math.PI * 0.5 || topLat < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Top latitude out of range");
+    if (bottomLat > Math.PI * 0.5 || bottomLat < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Bottom latitude out of range");
+    if (topLat < bottomLat)
+      throw new IllegalArgumentException("Top latitude less than bottom latitude");
+    if (leftLon < -Math.PI || leftLon > Math.PI)
+      throw new IllegalArgumentException("Left longitude out of range");
+    if (rightLon < -Math.PI || rightLon > Math.PI)
+      throw new IllegalArgumentException("Right longitude out of range");
+    double extent = rightLon - leftLon;
+    if (extent < 0.0) {
+      extent += 2.0 * Math.PI;
+    }
+    if (extent < Math.PI)
+      throw new IllegalArgumentException("Width of rectangle too small");
+
+    this.topLat = topLat;
+    this.bottomLat = bottomLat;
+    this.leftLon = leftLon;
+    this.rightLon = rightLon;
+
+    final double sinTopLat = Math.sin(topLat);
+    final double cosTopLat = Math.cos(topLat);
+    final double sinBottomLat = Math.sin(bottomLat);
+    final double cosBottomLat = Math.cos(bottomLat);
+    final double sinLeftLon = Math.sin(leftLon);
+    final double cosLeftLon = Math.cos(leftLon);
+    final double sinRightLon = Math.sin(rightLon);
+    final double cosRightLon = Math.cos(rightLon);
+
+    // Now build the four points
+    this.ULHC = new GeoPoint(planetModel, sinTopLat, sinLeftLon, cosTopLat, cosLeftLon, topLat, leftLon);
+    this.URHC = new GeoPoint(planetModel, sinTopLat, sinRightLon, cosTopLat, cosRightLon, topLat, rightLon);
+    this.LRHC = new GeoPoint(planetModel, sinBottomLat, sinRightLon, cosBottomLat, cosRightLon, bottomLat, rightLon);
+    this.LLHC = new GeoPoint(planetModel, sinBottomLat, sinLeftLon, cosBottomLat, cosLeftLon, bottomLat, leftLon);
+
+    final double middleLat = (topLat + bottomLat) * 0.5;
+    final double sinMiddleLat = Math.sin(middleLat);
+    this.cosMiddleLat = Math.cos(middleLat);
+    // Normalize
+    while (leftLon > rightLon) {
+      rightLon += Math.PI * 2.0;
+    }
+    final double middleLon = (leftLon + rightLon) * 0.5;
+    final double sinMiddleLon = Math.sin(middleLon);
+    final double cosMiddleLon = Math.cos(middleLon);
+
+    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinMiddleLon, cosMiddleLat, cosMiddleLon);
+
+    this.topPlane = new SidedPlane(centerPoint, planetModel, sinTopLat);
+    this.bottomPlane = new SidedPlane(centerPoint, planetModel, sinBottomLat);
+    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
+    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
+
+    this.topPlanePoints = new GeoPoint[]{ULHC, URHC};
+    this.bottomPlanePoints = new GeoPoint[]{LLHC, LRHC};
+    this.leftPlanePoints = new GeoPoint[]{ULHC, LLHC};
+    this.rightPlanePoints = new GeoPoint[]{URHC, LRHC};
+
+    this.eitherBound = new EitherBound();
+
+    this.edgePoints = new GeoPoint[]{ULHC};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    final double newTopLat = topLat + angle;
+    final double newBottomLat = bottomLat - angle;
+    // Figuring out when we escalate to a special case requires some prefiguring
+    double currentLonSpan = rightLon - leftLon;
+    if (currentLonSpan < 0.0)
+      currentLonSpan += Math.PI * 2.0;
+    double newLeftLon = leftLon - angle;
+    double newRightLon = rightLon + angle;
+    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
+      newLeftLon = -Math.PI;
+      newRightLon = Math.PI;
+    }
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return topPlane.isWithin(x, y, z) &&
+        bottomPlane.isWithin(x, y, z) &&
+        (leftPlane.isWithin(x, y, z) ||
+            rightPlane.isWithin(x, y, z));
+  }
+
+  @Override
+  public double getRadius() {
+    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
+    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
+    // the distance to the right or left edge from the center.
+    final double centerAngle = (rightLon - (rightLon + leftLon) * 0.5) * cosMiddleLat;
+    final double topAngle = centerPoint.arcDistance(URHC);
+    final double bottomAngle = centerPoint.arcDistance(LLHC);
+    return Math.max(centerAngle, Math.max(topAngle, bottomAngle));
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  /**
+   * Returns the center of a circle into which the area will be inscribed.
+   *
+   * @return the center.
+   */
+  @Override
+  public GeoPoint getCenter() {
+    return centerPoint;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    // Right and left bounds are essentially independent hemispheres; crossing into the wrong part of one
+    // requires crossing into the right part of the other.  So intersection can ignore the left/right bounds.
+    return p.intersects(planetModel, topPlane, notablePoints, topPlanePoints, bounds, bottomPlane, eitherBound) ||
+        p.intersects(planetModel, bottomPlane, notablePoints, bottomPlanePoints, bounds, topPlane, eitherBound) ||
+        p.intersects(planetModel, leftPlane, notablePoints, leftPlanePoints, bounds, topPlane, bottomPlane) ||
+        p.intersects(planetModel, rightPlane, notablePoints, rightPlanePoints, bounds, topPlane, bottomPlane);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds.isWide()
+      .addHorizontalPlane(planetModel, topLat, topPlane, bottomPlane, eitherBound)
+      .addVerticalPlane(planetModel, rightLon, rightPlane, topPlane, bottomPlane)
+      .addHorizontalPlane(planetModel, bottomLat, bottomPlane, topPlane, eitherBound)
+      .addVerticalPlane(planetModel, leftLon, leftPlane, topPlane, bottomPlane)
+      .addPoint(ULHC).addPoint(URHC).addPoint(LRHC).addPoint(LLHC);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    //System.err.println(this+" comparing to "+path);
+    final int insideRectangle = isShapeInsideBBox(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some inside");
+      return OVERLAPS;
+    }
+
+    final boolean insideShape = path.isWithin(ULHC);
+
+    if (insideRectangle == ALL_INSIDE && insideShape) {
+      //System.err.println(" both inside each other");
+      return OVERLAPS;
+    }
+
+    if (path.intersects(topPlane, topPlanePoints, bottomPlane, eitherBound) ||
+        path.intersects(bottomPlane, bottomPlanePoints, topPlane, eitherBound) ||
+        path.intersects(leftPlane, leftPlanePoints, topPlane, bottomPlane) ||
+        path.intersects(rightPlane, rightPlanePoints, topPlane, bottomPlane)) {
+      //System.err.println(" edges intersect");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      //System.err.println(" shape inside rectangle");
+      return WITHIN;
+    }
+
+    if (insideShape) {
+      //System.err.println(" rectangle inside shape");
+      return CONTAINS;
+    }
+
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    final double topDistance = distanceStyle.computeDistance(planetModel, topPlane, x,y,z, bottomPlane, eitherBound);
+    final double bottomDistance = distanceStyle.computeDistance(planetModel, bottomPlane, x,y,z, topPlane, eitherBound);
+    // Because the rectangle exceeds 180 degrees, it is safe to compute the horizontally 
+    // unbounded distance to both the left and the right and only take the minimum of the two.
+    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, topPlane, bottomPlane);
+    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, topPlane, bottomPlane);
+    
+    final double ULHCDistance = distanceStyle.computeDistance(ULHC, x,y,z);
+    final double URHCDistance = distanceStyle.computeDistance(URHC, x,y,z);
+    final double LRHCDistance = distanceStyle.computeDistance(LRHC, x,y,z);
+    final double LLHCDistance = distanceStyle.computeDistance(LLHC, x,y,z);
+    
+    return Math.min(
+      Math.min(
+        Math.min(topDistance, bottomDistance),
+        Math.min(leftDistance, rightDistance)),
+      Math.min(
+        Math.min(ULHCDistance, URHCDistance),
+        Math.min(LRHCDistance, LLHCDistance)));
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoWideRectangle))
+      return false;
+    GeoWideRectangle other = (GeoWideRectangle) o;
+    return super.equals(other) && other.ULHC.equals(ULHC) && other.LRHC.equals(LRHC);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + ULHC.hashCode();
+    result = 31 * result + LRHC.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoWideRectangle: {planetmodel=" + planetModel + ", toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + "), bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
+  }
+
+  /** A membership implementation representing a wide (more than 180) left/right bound.
+   */
+  protected class EitherBound implements Membership {
+    /** Constructor.
+      */
+    public EitherBound() {
+    }
+
+    @Override
+    public boolean isWithin(final Vector v) {
+      return leftPlane.isWithin(v) || rightPlane.isWithin(v);
+    }
+
+    @Override
+    public boolean isWithin(final double x, final double y, final double z) {
+      return leftPlane.isWithin(x, y, z) || rightPlane.isWithin(x, y, z);
+    }
+  }
+}
+  


[27/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 3a31a8c)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/PlanetModel.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/PlanetModel.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/PlanetModel.java
deleted file mode 100644
index 395fa15..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/PlanetModel.java
+++ /dev/null
@@ -1,277 +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.geo3d;
-
-/**
- * Holds mathematical constants associated with the model of a planet.
- * @lucene.experimental
- */
-public class PlanetModel {
-  
-  /** Planet model corresponding to sphere. */
-  public static final PlanetModel SPHERE = new PlanetModel(1.0,1.0);
-
-  /** Mean radius */
-  public static final double WGS84_MEAN = 6371009.0;
-  /** Polar radius */
-  public static final double WGS84_POLAR = 6356752.314245;
-  /** Equatorial radius */
-  public static final double WGS84_EQUATORIAL = 6378137.0;
-  /** Planet model corresponding to WGS84 */
-  public static final PlanetModel WGS84 = new PlanetModel(WGS84_EQUATORIAL/WGS84_MEAN,
-    WGS84_POLAR/WGS84_MEAN);
-
-  // Surface of the planet:
-  // x^2/a^2 + y^2/b^2 + z^2/c^2 = 1.0
-  // Scaling factors are a,b,c.  geo3d can only support models where a==b, so use ab instead.
-  
-  /** The x/y scaling factor */
-  public final double ab;
-  /** The z scaling factor */
-  public final double c;
-  /** The inverse of ab */
-  public final double inverseAb;
-  /** The inverse of c */
-  public final double inverseC;
-  /** The square of the inverse of ab */
-  public final double inverseAbSquared;
-  /** The square of the inverse of c */
-  public final double inverseCSquared;
-  /** The flattening value */
-  public final double flattening;
-  /** The square ratio */
-  public final double squareRatio;
-  
-  // We do NOT include radius, because all computations in geo3d are in radians, not meters.
-  
-  // Compute north and south pole for planet model, since these are commonly used.
-  
-  /** North pole */
-  public final GeoPoint NORTH_POLE;
-  /** South pole */
-  public final GeoPoint SOUTH_POLE;
-  /** Min X pole */
-  public final GeoPoint MIN_X_POLE;
-  /** Max X pole */
-  public final GeoPoint MAX_X_POLE;
-  /** Min Y pole */
-  public final GeoPoint MIN_Y_POLE;
-  /** Max Y pole */
-  public final GeoPoint MAX_Y_POLE;
-  
-  /** Constructor.
-   * @param ab is the x/y scaling factor.
-   * @param c is the z scaling factor.
-   */
-  public PlanetModel(final double ab, final double c) {
-    this.ab = ab;
-    this.c = c;
-    this.inverseAb = 1.0 / ab;
-    this.inverseC = 1.0 / c;
-    this.flattening = (ab - c) * inverseAb;
-    this.squareRatio = (ab * ab - c * c) / (c * c);
-    this.inverseAbSquared = inverseAb * inverseAb;
-    this.inverseCSquared = inverseC * inverseC;
-    this.NORTH_POLE = new GeoPoint(c, 0.0, 0.0, 1.0, Math.PI * 0.5, 0.0);
-    this.SOUTH_POLE = new GeoPoint(c, 0.0, 0.0, -1.0, -Math.PI * 0.5, 0.0);
-    this.MIN_X_POLE = new GeoPoint(ab, -1.0, 0.0, 0.0, 0.0, -Math.PI);
-    this.MAX_X_POLE = new GeoPoint(ab, 1.0, 0.0, 0.0, 0.0, 0.0);
-    this.MIN_Y_POLE = new GeoPoint(ab, 0.0, -1.0, 0.0, 0.0, -Math.PI * 0.5);
-    this.MAX_Y_POLE = new GeoPoint(ab, 0.0, 1.0, 0.0, 0.0, Math.PI * 0.5);
-  }
-  
-  /** Find the minimum magnitude of all points on the ellipsoid.
-   * @return the minimum magnitude for the planet.
-   */
-  public double getMinimumMagnitude() {
-    return Math.min(this.ab, this.c);
-  }
-
-  /** Find the maximum magnitude of all points on the ellipsoid.
-   * @return the maximum magnitude for the planet.
-   */
-  public double getMaximumMagnitude() {
-    return Math.max(this.ab, this.c);
-  }
-  
-  /** Find the minimum x value.
-   *@return the minimum X value.
-   */
-  public double getMinimumXValue() {
-    return -this.ab;
-  }
-  
-  /** Find the maximum x value.
-   *@return the maximum X value.
-   */
-  public double getMaximumXValue() {
-    return this.ab;
-  }
-
-  /** Find the minimum y value.
-   *@return the minimum Y value.
-   */
-  public double getMinimumYValue() {
-    return -this.ab;
-  }
-  
-  /** Find the maximum y value.
-   *@return the maximum Y value.
-   */
-  public double getMaximumYValue() {
-    return this.ab;
-  }
-  
-  /** Find the minimum z value.
-   *@return the minimum Z value.
-   */
-  public double getMinimumZValue() {
-    return -this.c;
-  }
-  
-  /** Find the maximum z value.
-   *@return the maximum Z value.
-   */
-  public double getMaximumZValue() {
-    return this.c;
-  }
-
-  /** Check if point is on surface.
-   * @param v is the point to check.
-   * @return true if the point is on the planet surface.
-   */
-  public boolean pointOnSurface(final Vector v) {
-    return pointOnSurface(v.x, v.y, v.z);
-  }
-  
-  /** Check if point is on surface.
-   * @param x is the x coord.
-   * @param y is the y coord.
-   * @param z is the z coord.
-   */
-  public boolean pointOnSurface(final double x, final double y, final double z) {
-    // Equation of planet surface is:
-    // x^2 / a^2 + y^2 / b^2 + z^2 / c^2 - 1 = 0
-    return Math.abs(x * x * inverseAb * inverseAb + y * y * inverseAb * inverseAb + z * z * inverseC * inverseC - 1.0) < Vector.MINIMUM_RESOLUTION;
-  }
-
-  /** Check if point is outside surface.
-   * @param v is the point to check.
-   * @return true if the point is outside the planet surface.
-   */
-  public boolean pointOutside(final Vector v) {
-    return pointOutside(v.x, v.y, v.z);
-  }
-  
-  /** Check if point is outside surface.
-   * @param x is the x coord.
-   * @param y is the y coord.
-   * @param z is the z coord.
-   */
-  public boolean pointOutside(final double x, final double y, final double z) {
-    // Equation of planet surface is:
-    // x^2 / a^2 + y^2 / b^2 + z^2 / c^2 - 1 = 0
-    return (x * x + y * y) * inverseAb * inverseAb + z * z * inverseC * inverseC - 1.0 > Vector.MINIMUM_RESOLUTION;
-  }
-  
-  /** Compute surface distance between two points.
-   * @param p1 is the first point.
-   * @param p2 is the second point.
-   * @return the adjusted angle, when multiplied by the mean earth radius, yields a surface distance.  This will differ
-   * from GeoPoint.arcDistance() only when the planet model is not a sphere. @see {@link org.apache.lucene.geo3d.GeoPoint#arcDistance(GeoPoint)}
-   */
-  public double surfaceDistance(final GeoPoint p1, final GeoPoint p2) {
-    final double latA = p1.getLatitude();
-    final double lonA = p1.getLongitude();
-    final double latB = p2.getLatitude();
-    final double lonB = p2.getLongitude();
-
-    final double L = lonB - lonA;
-    final double oF = 1.0 - this.flattening;
-    final double U1 = Math.atan(oF * Math.tan(latA));
-    final double U2 = Math.atan(oF * Math.tan(latB));
-    final double sU1 = Math.sin(U1);
-    final double cU1 = Math.cos(U1);
-    final double sU2 = Math.sin(U2);
-    final double cU2 = Math.cos(U2);
-
-    double sigma, sinSigma, cosSigma;
-    double cos2Alpha, cos2SigmaM;
-    
-    double lambda = L;
-    double iters = 100;
-
-    do {
-      final double sinLambda = Math.sin(lambda);
-      final double cosLambda = Math.cos(lambda);
-      sinSigma = Math.sqrt((cU2 * sinLambda) * (cU2 * sinLambda) + (cU1 * sU2 - sU1 * cU2 * cosLambda)
-          * (cU1 * sU2 - sU1 * cU2 * cosLambda));
-      if (Math.abs(sinSigma) < Vector.MINIMUM_RESOLUTION)
-        return 0.0;
-
-      cosSigma = sU1 * sU2 + cU1 * cU2 * cosLambda;
-      sigma = Math.atan2(sinSigma, cosSigma);
-      final double sinAlpha = cU1 * cU2 * sinLambda / sinSigma;
-      cos2Alpha = 1.0 - sinAlpha * sinAlpha;
-      cos2SigmaM = cosSigma - 2.0 * sU1 * sU2 / cos2Alpha;
-
-      final double c = this.flattening * 0.625 * cos2Alpha * (4.0 + this.flattening * (4.0 - 3.0 * cos2Alpha));
-      final double lambdaP = lambda;
-      lambda = L + (1.0 - c) * this.flattening * sinAlpha * (sigma + c * sinSigma * (cos2SigmaM + c * cosSigma *
-          (-1.0 + 2.0 * cos2SigmaM * cos2SigmaM)));
-      if (Math.abs(lambda - lambdaP) < Vector.MINIMUM_RESOLUTION)
-        break;
-    } while (--iters > 0);
-
-    if (iters == 0)
-      return 0.0;
-
-    final double uSq = cos2Alpha * this.squareRatio;
-    final double A = 1.0 + uSq * 0.00006103515625 * (4096.0 + uSq * (-768.0 + uSq * (320.0 - 175.0 * uSq)));
-    final double B = uSq * 0.0009765625 * (256.0 + uSq * (-128.0 + uSq * (74.0 - 47.0 * uSq)));
-    final double deltaSigma = B * sinSigma * (cos2SigmaM + B * 0.25 * (cosSigma * (-1.0 + 2.0 * cos2SigmaM * cos2SigmaM) - B * 0.16666666666666666666667 * cos2SigmaM
-            * (-3.0 + 4.0 * sinSigma * sinSigma) * (-3.0 + 4.0 * cos2SigmaM * cos2SigmaM)));
-
-    return this.c * A * (sigma - deltaSigma);
-  }
-
-  @Override
-  public boolean equals(final Object o) {
-    if (!(o instanceof PlanetModel))
-      return false;
-    final PlanetModel other = (PlanetModel)o;
-    return ab == other.ab && c == other.c;
-  }
-  
-  @Override
-  public int hashCode() {
-    return Double.hashCode(ab) + Double.hashCode(c);
-  }
-  
-  @Override
-  public String toString() {
-    if (this.equals(SPHERE)) {
-      return "PlanetModel.SPHERE";
-    } else if (this.equals(WGS84)) {
-      return "PlanetModel.WGS84";
-    } else {
-      return "PlanetModel(ab="+ab+" c="+c+")";
-    }
-  }
-}
-
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/PointInGeo3DShapeQuery.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/PointInGeo3DShapeQuery.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/PointInGeo3DShapeQuery.java
deleted file mode 100644
index 9e2132d..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/PointInGeo3DShapeQuery.java
+++ /dev/null
@@ -1,210 +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.geo3d;
-
-import java.io.IOException;
-
-import org.apache.lucene.index.PointValues.IntersectVisitor;
-import org.apache.lucene.index.PointValues;
-import org.apache.lucene.index.PointValues.Relation;
-import org.apache.lucene.index.LeafReader;
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.search.ConstantScoreScorer;
-import org.apache.lucene.search.ConstantScoreWeight;
-import org.apache.lucene.search.IndexSearcher;
-import org.apache.lucene.search.Query;
-import org.apache.lucene.search.Scorer;
-import org.apache.lucene.search.Weight;
-import org.apache.lucene.util.DocIdSetBuilder;
-import org.apache.lucene.util.NumericUtils;
-
-/** Finds all previously indexed points that fall within the specified polygon.
- *
- * <p>The field must be indexed using {@link Geo3DPoint}.
- *
- * @lucene.experimental */
-
-class PointInGeo3DShapeQuery extends Query {
-  final String field;
-  final GeoShape shape;
-
-  /** The lats/lons must be clockwise or counter-clockwise. */
-  public PointInGeo3DShapeQuery(String field, GeoShape shape) {
-    this.field = field;
-    this.shape = shape;
-
-    if (shape instanceof BasePlanetObject) {
-      BasePlanetObject planetObject = (BasePlanetObject) shape;
-      if (planetObject.getPlanetModel().equals(PlanetModel.WGS84) == false) {
-        throw new IllegalArgumentException("this qurey requires PlanetModel.WGS84, but got: " + planetObject.getPlanetModel());
-      }
-    }
-  }
-
-  @Override
-  public Weight createWeight(IndexSearcher searcher, boolean needsScores) throws IOException {
-
-    // I don't use RandomAccessWeight here: it's no good to approximate with "match all docs"; this is an inverted structure and should be
-    // used in the first pass:
-
-    return new ConstantScoreWeight(this) {
-
-      @Override
-      public Scorer scorer(LeafReaderContext context) throws IOException {
-        LeafReader reader = context.reader();
-        PointValues values = reader.getPointValues();
-        if (values == null) {
-          return null;
-        }
-
-        /*
-        XYZBounds bounds = new XYZBounds();
-        shape.getBounds(bounds);
-
-        final double planetMax = planetModel.getMaximumMagnitude();
-        if (planetMax != treeDV.planetMax) {
-          throw new IllegalStateException(planetModel + " is not the same one used during indexing: planetMax=" + planetMax + " vs indexing planetMax=" + treeDV.planetMax);
-        }
-        */
-
-        /*
-        GeoArea xyzSolid = GeoAreaFactory.makeGeoArea(planetModel,
-                                                      bounds.getMinimumX(),
-                                                      bounds.getMaximumX(),
-                                                      bounds.getMinimumY(),
-                                                      bounds.getMaximumY(),
-                                                      bounds.getMinimumZ(),
-                                                      bounds.getMaximumZ());
-
-        assert xyzSolid.getRelationship(shape) == GeoArea.WITHIN || xyzSolid.getRelationship(shape) == GeoArea.OVERLAPS: "expected WITHIN (1) or OVERLAPS (2) but got " + xyzSolid.getRelationship(shape) + "; shape="+shape+"; XYZSolid="+xyzSolid;
-        */
-
-        double planetMax = PlanetModel.WGS84.getMaximumMagnitude();
-
-        DocIdSetBuilder result = new DocIdSetBuilder(reader.maxDoc());
-
-        values.intersect(field,
-                         new IntersectVisitor() {
-
-                           @Override
-                           public void visit(int docID) {
-                             result.add(docID);
-                           }
-
-                           @Override
-                           public void visit(int docID, byte[] packedValue) {
-                             assert packedValue.length == 12;
-                             double x = Geo3DPoint.decodeDimension(packedValue, 0);
-                             double y = Geo3DPoint.decodeDimension(packedValue, Integer.BYTES);
-                             double z = Geo3DPoint.decodeDimension(packedValue, 2 * Integer.BYTES);
-                             if (shape.isWithin(x, y, z)) {
-                               result.add(docID);
-                             }
-                           }
-
-                           @Override
-                           public Relation compare(byte[] minPackedValue, byte[] maxPackedValue) {
-                             // Because the dimensional format operates in quantized (64 bit -> 32 bit) space, and the cell bounds
-                             // here are inclusive, we need to extend the bounds to the largest un-quantized values that
-                             // could quantize into these bounds.  The encoding (Geo3DUtil.encodeValue) does
-                             // a Math.round from double to long, so e.g. 1.4 -> 1, and -1.4 -> -1:
-                             double xMin = Geo3DUtil.decodeValueMin(planetMax, NumericUtils.sortableBytesToInt(minPackedValue, 0));
-                             double xMax = Geo3DUtil.decodeValueMax(planetMax, NumericUtils.sortableBytesToInt(maxPackedValue, 0));
-                             double yMin = Geo3DUtil.decodeValueMin(planetMax, NumericUtils.sortableBytesToInt(minPackedValue, 1 * Integer.BYTES));
-                             double yMax = Geo3DUtil.decodeValueMax(planetMax, NumericUtils.sortableBytesToInt(maxPackedValue, 1 * Integer.BYTES));
-                             double zMin = Geo3DUtil.decodeValueMin(planetMax, NumericUtils.sortableBytesToInt(minPackedValue, 2 * Integer.BYTES));
-                             double zMax = Geo3DUtil.decodeValueMax(planetMax, NumericUtils.sortableBytesToInt(maxPackedValue, 2 * Integer.BYTES));
-
-                             //System.out.println("  compare: x=" + cellXMin + "-" + cellXMax + " y=" + cellYMin + "-" + cellYMax + " z=" + cellZMin + "-" + cellZMax);
-                             assert xMin <= xMax;
-                             assert yMin <= yMax;
-                             assert zMin <= zMax;
-
-                             GeoArea xyzSolid = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84, xMin, xMax, yMin, yMax, zMin, zMax);
-
-                             switch(xyzSolid.getRelationship(shape)) {
-                             case GeoArea.CONTAINS:
-                               // Shape fully contains the cell
-                               //System.out.println("    inside");
-                               return Relation.CELL_INSIDE_QUERY;
-                             case GeoArea.OVERLAPS:
-                               // They do overlap but neither contains the other:
-                               //System.out.println("    crosses1");
-                               return Relation.CELL_CROSSES_QUERY;
-                             case GeoArea.WITHIN:
-                               // Cell fully contains the shape:
-                               //System.out.println("    crosses2");
-                               // return Relation.SHAPE_INSIDE_CELL;
-                               return Relation.CELL_CROSSES_QUERY;
-                             case GeoArea.DISJOINT:
-                               // They do not overlap at all
-                               //System.out.println("    outside");
-                               return Relation.CELL_OUTSIDE_QUERY;
-                             default:
-                               assert false;
-                               return Relation.CELL_CROSSES_QUERY;
-                             }
-                           }
-                         });
-
-        return new ConstantScoreScorer(this, score(), result.build().iterator());
-      }
-    };
-  }
-
-  public String getField() {
-    return field;
-  }
-
-  public GeoShape getShape() {
-    return shape;
-  }
-
-  @Override
-  @SuppressWarnings({"unchecked","rawtypes"})
-  public boolean equals(Object o) {
-    if (this == o) return true;
-    if (o == null || getClass() != o.getClass()) return false;
-    if (!super.equals(o)) return false;
-
-    PointInGeo3DShapeQuery that = (PointInGeo3DShapeQuery) o;
-
-    return shape.equals(that.shape);
-  }
-
-  @Override
-  public final int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + shape.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString(String field) {
-    final StringBuilder sb = new StringBuilder();
-    sb.append(getClass().getSimpleName());
-    sb.append(':');
-    if (this.field.equals(field) == false) {
-      sb.append(" field=");
-      sb.append(this.field);
-      sb.append(':');
-    }
-    sb.append(" Shape: ");
-    sb.append(shape);
-    return sb.toString();
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/SidedPlane.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/SidedPlane.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/SidedPlane.java
deleted file mode 100755
index 7fc543d..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/SidedPlane.java
+++ /dev/null
@@ -1,175 +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.geo3d;
-
-/**
- * Combination of a plane, and a sign value indicating what evaluation values are on the correct
- * side of the plane.
- *
- * @lucene.experimental
- */
-public class SidedPlane extends Plane implements Membership {
-  /** The sign value for evaluation of a point on the correct side of the plane */
-  public final double sigNum;
-
-  /**
-   * Construct a SidedPlane identical to an existing one, but reversed.
-   *
-   * @param sidedPlane is the existing plane.
-   */
-  public SidedPlane(SidedPlane sidedPlane) {
-    super(sidedPlane, sidedPlane.D);
-    this.sigNum = -sidedPlane.sigNum;
-  }
-
-  /**
-   * Construct a sided plane from a pair of vectors describing points, and including
-   * origin, plus a point p which describes the side.
-   *
-   * @param p point to evaluate
-   * @param A is the first in-plane point
-   * @param B is the second in-plane point
-   */
-  public SidedPlane(Vector p, Vector A, Vector B) {
-    super(A, B);
-    sigNum = Math.signum(evaluate(p));
-    if (sigNum == 0.0)
-      throw new IllegalArgumentException("Cannot determine sidedness because check point is on plane.");
-  }
-
-  /**
-   * Construct a sided plane from a point and a Z coordinate.
-   *
-   * @param p      point to evaluate.
-   * @param planetModel is the planet model.
-   * @param sinLat is the sin of the latitude of the plane.
-   */
-  public SidedPlane(Vector p, final PlanetModel planetModel, double sinLat) {
-    super(planetModel, sinLat);
-    sigNum = Math.signum(evaluate(p));
-    if (sigNum == 0.0)
-      throw new IllegalArgumentException("Cannot determine sidedness because check point is on plane.");
-  }
-
-  /**
-   * Construct a sided vertical plane from a point and specified x and y coordinates.
-   *
-   * @param p point to evaluate.
-   * @param x is the specified x.
-   * @param y is the specified y.
-   */
-  public SidedPlane(Vector p, double x, double y) {
-    super(x, y);
-    sigNum = Math.signum(evaluate(p));
-    if (sigNum == 0.0)
-      throw new IllegalArgumentException("Cannot determine sidedness because check point is on plane.");
-  }
-
-  /**
-   * Construct a sided plane with a normal vector and offset.
-   *
-   * @param p point to evaluate.
-   * @param v is the normal vector.
-   * @param D is the origin offset for the plan.
-   */
-  public SidedPlane(Vector p, Vector v, double D) {
-    super(v, D);
-    sigNum = Math.signum(evaluate(p));
-    if (sigNum == 0.0)
-      throw new IllegalArgumentException("Cannot determine sidedness because check point is on plane.");
-  }
-
-  /**
-   * Construct a sided plane with a normal vector and offset.
-   *
-   * @param pX X coord of point to evaluate.
-   * @param pY Y coord of point to evaluate.
-   * @param pZ Z coord of point to evaluate.
-   * @param v is the normal vector.
-   * @param D is the origin offset for the plan.
-   */
-  public SidedPlane(double pX, double pY, double pZ, Vector v, double D) {
-    super(v, D);
-    sigNum = Math.signum(evaluate(pX,pY,pZ));
-    if (sigNum == 0.0)
-      throw new IllegalArgumentException("Cannot determine sidedness because check point is on plane.");
-  }
-
-  /** Construct a sided plane from two points and a third normal vector.
-   */
-  public static SidedPlane constructNormalizedPerpendicularSidedPlane(final Vector insidePoint,
-    final Vector normalVector, final Vector point1, final Vector point2) {
-    final Vector pointsVector = new Vector(point1.x - point2.x, point1.y - point2.y, point1.z - point2.z);
-    final Vector newNormalVector = new Vector(normalVector, pointsVector);
-    try {
-      // To construct the plane, we now just need D, which is simply the negative of the evaluation of the circle normal vector at one of the points.
-      return new SidedPlane(insidePoint, newNormalVector, -newNormalVector.dotProduct(point1));
-    } catch (IllegalArgumentException e) {
-      return null;
-    }
-  }
-  
-  /** Construct a sided plane from three points.
-   */
-  public static SidedPlane constructNormalizedThreePointSidedPlane(final Vector insidePoint,
-    final Vector point1, final Vector point2, final Vector point3) {
-    try {
-      final Vector planeNormal = new Vector(
-        new Vector(point1.x - point2.x, point1.y - point2.y, point1.z - point2.z),
-        new Vector(point2.x - point3.x, point2.y - point3.y, point2.z - point3.z));
-      return new SidedPlane(insidePoint, planeNormal, -planeNormal.dotProduct(point2));
-    } catch (IllegalArgumentException e) {
-      return null;
-    }
-  }
-
-  @Override
-  public boolean isWithin(double x, double y, double z) {
-    double evalResult = evaluate(x, y, z);
-    if (Math.abs(evalResult) < MINIMUM_RESOLUTION)
-      return true;
-    double sigNum = Math.signum(evalResult);
-    return sigNum == this.sigNum;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) return true;
-    if (!(o instanceof SidedPlane)) return false;
-    if (!super.equals(o)) return false;
-
-    SidedPlane that = (SidedPlane) o;
-
-    return Double.compare(that.sigNum, sigNum) == 0;
-
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    long temp;
-    temp = Double.doubleToLongBits(sigNum);
-    result = 31 * result + (int) (temp ^ (temp >>> 32));
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "[A=" + x + ", B=" + y + ", C=" + z + ", D=" + D + ", side=" + sigNum + "]";
-  }
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/StandardXYZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/StandardXYZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/StandardXYZSolid.java
deleted file mode 100644
index cd54225..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/StandardXYZSolid.java
+++ /dev/null
@@ -1,417 +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.geo3d;
-
-/**
- * 3D rectangle, bounded on six sides by X,Y,Z limits
- *
- * @lucene.internal
- */
-public class StandardXYZSolid extends BaseXYZSolid {
-
-  /** Whole world? */
-  protected final boolean isWholeWorld;
-  /** Min-X plane */
-  protected final SidedPlane minXPlane;
-  /** Max-X plane */
-  protected final SidedPlane maxXPlane;
-  /** Min-Y plane */
-  protected final SidedPlane minYPlane;
-  /** Max-Y plane */
-  protected final SidedPlane maxYPlane;
-  /** Min-Z plane */
-  protected final SidedPlane minZPlane;
-  /** Max-Z plane */
-  protected final SidedPlane maxZPlane;
-  
-  /** These are the edge points of the shape, which are defined to be at least one point on
-   * each surface area boundary.  In the case of a solid, this includes points which represent
-   * the intersection of XYZ bounding planes and the planet, as well as points representing
-   * the intersection of single bounding planes with the planet itself.
-   */
-  protected final GeoPoint[] edgePoints;
-
-  /** Notable points for minXPlane */
-  protected final GeoPoint[] notableMinXPoints;
-  /** Notable points for maxXPlane */
-  protected final GeoPoint[] notableMaxXPoints;
-  /** Notable points for minYPlane */
-  protected final GeoPoint[] notableMinYPoints;
-  /** Notable points for maxYPlane */
-  protected final GeoPoint[] notableMaxYPoints;
-  /** Notable points for minZPlane */
-  protected final GeoPoint[] notableMinZPoints;
-  /** Notable points for maxZPlane */
-  protected final GeoPoint[] notableMaxZPoints;
-
-  /**
-   * Sole constructor
-   *
-   *@param planetModel is the planet model.
-   *@param minX is the minimum X value.
-   *@param maxX is the maximum X value.
-   *@param minY is the minimum Y value.
-   *@param maxY is the maximum Y value.
-   *@param minZ is the minimum Z value.
-   *@param maxZ is the maximum Z value.
-   */
-  public StandardXYZSolid(final PlanetModel planetModel,
-    final double minX,
-    final double maxX,
-    final double minY,
-    final double maxY,
-    final double minZ,
-    final double maxZ) {
-    super(planetModel);
-    // Argument checking
-    if (maxX - minX < Vector.MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("X values in wrong order or identical");
-    if (maxY - minY < Vector.MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("Y values in wrong order or identical");
-    if (maxZ - minZ < Vector.MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("Z values in wrong order or identical");
-
-    final double worldMinX = planetModel.getMinimumXValue();
-    final double worldMaxX = planetModel.getMaximumXValue();
-    final double worldMinY = planetModel.getMinimumYValue();
-    final double worldMaxY = planetModel.getMaximumYValue();
-    final double worldMinZ = planetModel.getMinimumZValue();
-    final double worldMaxZ = planetModel.getMaximumZValue();
-    
-    // We must distinguish between the case where the solid represents the entire world,
-    // and when the solid has no overlap with any part of the surface.  In both cases,
-    // there will be no edgepoints.
-    isWholeWorld =
-        (minX - worldMinX < -Vector.MINIMUM_RESOLUTION) &&
-        (maxX - worldMaxX > Vector.MINIMUM_RESOLUTION) &&
-        (minY - worldMinY < -Vector.MINIMUM_RESOLUTION) &&
-        (maxY - worldMaxY > Vector.MINIMUM_RESOLUTION) &&
-        (minZ - worldMinZ < -Vector.MINIMUM_RESOLUTION) &&
-        (maxZ - worldMaxZ > Vector.MINIMUM_RESOLUTION);
-
-    if (isWholeWorld) {
-      minXPlane = null;
-      maxXPlane = null;
-      minYPlane = null;
-      maxYPlane = null;
-      minZPlane = null;
-      maxZPlane = null;
-      notableMinXPoints = null;
-      notableMaxXPoints = null;
-      notableMinYPoints = null;
-      notableMaxYPoints = null;
-      notableMinZPoints = null;
-      notableMaxZPoints = null;
-      edgePoints = null;
-    } else {
-      // Construct the planes
-      minXPlane = new SidedPlane(maxX,0.0,0.0,xUnitVector,-minX);
-      maxXPlane = new SidedPlane(minX,0.0,0.0,xUnitVector,-maxX);
-      minYPlane = new SidedPlane(0.0,maxY,0.0,yUnitVector,-minY);
-      maxYPlane = new SidedPlane(0.0,minY,0.0,yUnitVector,-maxY);
-      minZPlane = new SidedPlane(0.0,0.0,maxZ,zUnitVector,-minZ);
-      maxZPlane = new SidedPlane(0.0,0.0,minZ,zUnitVector,-maxZ);
-      
-      // We need at least one point on the planet surface for each manifestation of the shape.
-      // There can be up to 2 (on opposite sides of the world).  But we have to go through
-      // 12 combinations of adjacent planes in order to find out if any have 2 intersection solution.
-      // Typically, this requires 12 square root operations. 
-      final GeoPoint[] minXminY = minXPlane.findIntersections(planetModel,minYPlane,maxXPlane,maxYPlane,minZPlane,maxZPlane);
-      final GeoPoint[] minXmaxY = minXPlane.findIntersections(planetModel,maxYPlane,maxXPlane,minYPlane,minZPlane,maxZPlane);
-      final GeoPoint[] minXminZ = minXPlane.findIntersections(planetModel,minZPlane,maxXPlane,maxZPlane,minYPlane,maxYPlane);
-      final GeoPoint[] minXmaxZ = minXPlane.findIntersections(planetModel,maxZPlane,maxXPlane,minZPlane,minYPlane,maxYPlane);
-
-      final GeoPoint[] maxXminY = maxXPlane.findIntersections(planetModel,minYPlane,minXPlane,maxYPlane,minZPlane,maxZPlane);
-      final GeoPoint[] maxXmaxY = maxXPlane.findIntersections(planetModel,maxYPlane,minXPlane,minYPlane,minZPlane,maxZPlane);
-      final GeoPoint[] maxXminZ = maxXPlane.findIntersections(planetModel,minZPlane,minXPlane,maxZPlane,minYPlane,maxYPlane);
-      final GeoPoint[] maxXmaxZ = maxXPlane.findIntersections(planetModel,maxZPlane,minXPlane,minZPlane,minYPlane,maxYPlane);
-      
-      final GeoPoint[] minYminZ = minYPlane.findIntersections(planetModel,minZPlane,maxYPlane,maxZPlane,minXPlane,maxXPlane);
-      final GeoPoint[] minYmaxZ = minYPlane.findIntersections(planetModel,maxZPlane,maxYPlane,minZPlane,minXPlane,maxXPlane);
-      final GeoPoint[] maxYminZ = maxYPlane.findIntersections(planetModel,minZPlane,minYPlane,maxZPlane,minXPlane,maxXPlane);
-      final GeoPoint[] maxYmaxZ = maxYPlane.findIntersections(planetModel,maxZPlane,minYPlane,minZPlane,minXPlane,maxXPlane);
-      
-      notableMinXPoints = glueTogether(minXminY, minXmaxY, minXminZ, minXmaxZ);
-      notableMaxXPoints = glueTogether(maxXminY, maxXmaxY, maxXminZ, maxXmaxZ);
-      notableMinYPoints = glueTogether(minXminY, maxXminY, minYminZ, minYmaxZ);
-      notableMaxYPoints = glueTogether(minXmaxY, maxXmaxY, maxYminZ, maxYmaxZ);
-      notableMinZPoints = glueTogether(minXminZ, maxXminZ, minYminZ, maxYminZ);
-      notableMaxZPoints = glueTogether(minXmaxZ, maxXmaxZ, minYmaxZ, maxYmaxZ);
-
-      // Now, compute the edge points.
-      // This is the trickiest part of setting up an XYZSolid.  We've computed intersections already, so
-      // we'll start there.
-      // There can be a number of shapes, each of which needs an edgepoint.  Each side by itself might contribute
-      // an edgepoint, for instance, if the plane describing that side intercepts the planet in such a way that the ellipse
-      // of interception does not meet any other planes.  Plane intersections can each contribute 0, 1, or 2 edgepoints.
-      //
-      // All of this makes for a lot of potential edgepoints, but I believe these can be pruned back with careful analysis.
-      // I haven't yet done that analysis, however, so I will treat them all as individual edgepoints.
-      
-      // The cases we are looking for are when the four corner points for any given
-      // plane are all outside of the world, AND that plane intersects the world.
-      // There are eight corner points all told; we must evaluate these WRT the planet surface.
-      final boolean minXminYminZ = planetModel.pointOutside(minX, minY, minZ);
-      final boolean minXminYmaxZ = planetModel.pointOutside(minX, minY, maxZ);
-      final boolean minXmaxYminZ = planetModel.pointOutside(minX, maxY, minZ);
-      final boolean minXmaxYmaxZ = planetModel.pointOutside(minX, maxY, maxZ);
-      final boolean maxXminYminZ = planetModel.pointOutside(maxX, minY, minZ);
-      final boolean maxXminYmaxZ = planetModel.pointOutside(maxX, minY, maxZ);
-      final boolean maxXmaxYminZ = planetModel.pointOutside(maxX, maxY, minZ);
-      final boolean maxXmaxYmaxZ = planetModel.pointOutside(maxX, maxY, maxZ);
-        
-      // Look at single-plane/world intersections.
-      // We detect these by looking at the world model and noting its x, y, and z bounds.
-
-      final GeoPoint[] minXEdges;
-      if (minX - worldMinX >= -Vector.MINIMUM_RESOLUTION && minX - worldMaxX <= Vector.MINIMUM_RESOLUTION &&
-        minY < 0.0 && maxY > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
-        minXminYminZ && minXminYmaxZ && minXmaxYminZ && minXmaxYmaxZ) {
-        // Find any point on the minX plane that intersects the world
-        // First construct a perpendicular plane that will allow us to find a sample point.
-        // This plane is vertical and goes through the points (0,0,0) and (1,0,0)
-        // Then use it to compute a sample point.
-        final GeoPoint intPoint = minXPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
-        if (intPoint != null) {
-          minXEdges = new GeoPoint[]{intPoint};
-        } else {
-          // No intersection found?
-          minXEdges = EMPTY_POINTS;
-        }
-      } else {
-        minXEdges = EMPTY_POINTS;
-      }
-      
-      final GeoPoint[] maxXEdges;
-      if (maxX - worldMinX >= -Vector.MINIMUM_RESOLUTION && maxX - worldMaxX <= Vector.MINIMUM_RESOLUTION &&
-        minY < 0.0 && maxY > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
-        maxXminYminZ && maxXminYmaxZ && maxXmaxYminZ && maxXmaxYmaxZ) {
-        // Find any point on the maxX plane that intersects the world
-        // First construct a perpendicular plane that will allow us to find a sample point.
-        // This plane is vertical and goes through the points (0,0,0) and (1,0,0)
-        // Then use it to compute a sample point.
-        final GeoPoint intPoint = maxXPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
-        if (intPoint != null) {
-          maxXEdges = new GeoPoint[]{intPoint};
-        } else {
-          maxXEdges = EMPTY_POINTS;
-        }
-      } else {
-        maxXEdges = EMPTY_POINTS;
-      }
-      
-      final GeoPoint[] minYEdges;
-      if (minY - worldMinY >= -Vector.MINIMUM_RESOLUTION && minY - worldMaxY <= Vector.MINIMUM_RESOLUTION &&
-        minX < 0.0 && maxX > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
-        minXminYminZ && minXminYmaxZ && maxXminYminZ && maxXminYmaxZ) {
-        // Find any point on the minY plane that intersects the world
-        // First construct a perpendicular plane that will allow us to find a sample point.
-        // This plane is vertical and goes through the points (0,0,0) and (0,1,0)
-        // Then use it to compute a sample point.
-        final GeoPoint intPoint = minYPlane.getSampleIntersectionPoint(planetModel, yVerticalPlane);
-        if (intPoint != null) {
-          minYEdges = new GeoPoint[]{intPoint};
-        } else {
-          minYEdges = EMPTY_POINTS;
-        }
-      } else {
-        minYEdges = EMPTY_POINTS;
-      }
-      
-      final GeoPoint[] maxYEdges;
-      if (maxY - worldMinY >= -Vector.MINIMUM_RESOLUTION && maxY - worldMaxY <= Vector.MINIMUM_RESOLUTION &&
-        minX < 0.0 && maxX > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
-        minXmaxYminZ && minXmaxYmaxZ && maxXmaxYminZ && maxXmaxYmaxZ) {
-        // Find any point on the maxY plane that intersects the world
-        // First construct a perpendicular plane that will allow us to find a sample point.
-        // This plane is vertical and goes through the points (0,0,0) and (0,1,0)
-        // Then use it to compute a sample point.
-        final GeoPoint intPoint = maxYPlane.getSampleIntersectionPoint(planetModel, yVerticalPlane);
-        if (intPoint != null) {
-          maxYEdges = new GeoPoint[]{intPoint};
-        } else {
-          maxYEdges = EMPTY_POINTS;
-        }
-      } else {
-        maxYEdges = EMPTY_POINTS;
-      }
-      
-      final GeoPoint[] minZEdges;
-      if (minZ - worldMinZ >= -Vector.MINIMUM_RESOLUTION && minZ - worldMaxZ <= Vector.MINIMUM_RESOLUTION &&
-        minX < 0.0 && maxX > 0.0 && minY < 0.0 && maxY > 0.0 &&
-        minXminYminZ && minXmaxYminZ && maxXminYminZ && maxXmaxYminZ) {
-        // Find any point on the minZ plane that intersects the world
-        // First construct a perpendicular plane that will allow us to find a sample point.
-        // This plane is vertical and goes through the points (0,0,0) and (1,0,0)
-        // Then use it to compute a sample point.
-        final GeoPoint intPoint = minZPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
-        if (intPoint != null) {
-          minZEdges = new GeoPoint[]{intPoint};
-        } else {
-          minZEdges = EMPTY_POINTS;
-        }
-      } else {
-        minZEdges = EMPTY_POINTS;
-      }
-      
-      final GeoPoint[] maxZEdges;
-      if (maxZ - worldMinZ >= -Vector.MINIMUM_RESOLUTION && maxZ - worldMaxZ <= Vector.MINIMUM_RESOLUTION &&
-        minX < 0.0 && maxX > 0.0 && minY < 0.0 && maxY > 0.0 &&
-        minXminYmaxZ && minXmaxYmaxZ && maxXminYmaxZ && maxXmaxYmaxZ) {
-        // Find any point on the maxZ plane that intersects the world
-        // First construct a perpendicular plane that will allow us to find a sample point.
-        // This plane is vertical and goes through the points (0,0,0) and (1,0,0) (that is, its orientation doesn't matter)
-        // Then use it to compute a sample point.
-        final GeoPoint intPoint = maxZPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
-        if (intPoint != null) {
-          maxZEdges = new GeoPoint[]{intPoint};
-        } else {
-          maxZEdges = EMPTY_POINTS;
-        }
-      } else {
-        maxZEdges = EMPTY_POINTS;
-      }
-      
-      // Glue everything together.  This is not a minimal set of edgepoints, as of now, but it does completely describe all shapes on the
-      // planet.
-      this.edgePoints = glueTogether(minXminY, minXmaxY, minXminZ, minXmaxZ,
-        maxXminY, maxXmaxY, maxXminZ, maxXmaxZ,
-        minYminZ, minYmaxZ, maxYminZ, maxYmaxZ,
-        minXEdges, maxXEdges, minYEdges, maxYEdges, minZEdges, maxZEdges);
-    }
-  }
-
-  @Override
-  protected GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-  
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    if (isWholeWorld) {
-      return true;
-    }
-    return minXPlane.isWithin(x, y, z) &&
-      maxXPlane.isWithin(x, y, z) &&
-      minYPlane.isWithin(x, y, z) &&
-      maxYPlane.isWithin(x, y, z) &&
-      minZPlane.isWithin(x, y, z) &&
-      maxZPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    if (isWholeWorld) {
-      if (path.getEdgePoints().length > 0)
-        return WITHIN;
-      return OVERLAPS;
-    }
-    
-    /*
-    for (GeoPoint p : getEdgePoints()) {
-      System.err.println(" Edge point "+p+" path.isWithin()? "+path.isWithin(p));
-    }
-    
-    for (GeoPoint p : path.getEdgePoints()) {
-      System.err.println(" path edge point "+p+" isWithin()? "+isWithin(p)+" minx="+minXPlane.evaluate(p)+" maxx="+maxXPlane.evaluate(p)+" miny="+minYPlane.evaluate(p)+" maxy="+maxYPlane.evaluate(p)+" minz="+minZPlane.evaluate(p)+" maxz="+maxZPlane.evaluate(p));
-    }
-    */
-    
-    //System.err.println(this+" getrelationship with "+path);
-    final int insideRectangle = isShapeInsideArea(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some shape points inside area");
-      return OVERLAPS;
-    }
-
-    // Figure out if the entire XYZArea is contained by the shape.
-    final int insideShape = isAreaInsideShape(path);
-    if (insideShape == SOME_INSIDE) {
-      //System.err.println(" some area points inside shape");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
-      //System.err.println(" inside of each other");
-      return OVERLAPS;
-    }
-
-    if (path.intersects(minXPlane, notableMinXPoints, maxXPlane, minYPlane, maxYPlane, minZPlane, maxZPlane) ||
-        path.intersects(maxXPlane, notableMaxXPoints, minXPlane, minYPlane, maxYPlane, minZPlane, maxZPlane) ||
-        path.intersects(minYPlane, notableMinYPoints, maxYPlane, minXPlane, maxXPlane, minZPlane, maxZPlane) ||
-        path.intersects(maxYPlane, notableMaxYPoints, minYPlane, minXPlane, maxXPlane, minZPlane, maxZPlane) ||
-        path.intersects(minZPlane, notableMinZPoints, maxZPlane, minXPlane, maxXPlane, minYPlane, maxYPlane) ||
-        path.intersects(maxZPlane, notableMaxZPoints, minZPlane, minXPlane, maxXPlane, minYPlane, maxYPlane)) {
-      //System.err.println(" edges intersect");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      //System.err.println(" all shape points inside area");
-      return WITHIN;
-    }
-
-    if (insideShape == ALL_INSIDE) {
-      //System.err.println(" all area points inside shape");
-      return CONTAINS;
-    }
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof StandardXYZSolid))
-      return false;
-    StandardXYZSolid other = (StandardXYZSolid) o;
-    if (!super.equals(other) ||
-      other.isWholeWorld != isWholeWorld) {
-      return false;
-    }
-    if (!isWholeWorld) {
-      return other.minXPlane.equals(minXPlane) &&
-        other.maxXPlane.equals(maxXPlane) &&
-        other.minYPlane.equals(minYPlane) &&
-        other.maxYPlane.equals(maxYPlane) &&
-        other.minZPlane.equals(minZPlane) &&
-        other.maxZPlane.equals(maxZPlane);
-    }
-    return true;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + (isWholeWorld?1:0);
-    if (!isWholeWorld) {
-      result = 31 * result  + minXPlane.hashCode();
-      result = 31 * result  + maxXPlane.hashCode();
-      result = 31 * result  + minYPlane.hashCode();
-      result = 31 * result  + maxYPlane.hashCode();
-      result = 31 * result  + minZPlane.hashCode();
-      result = 31 * result  + maxZPlane.hashCode();
-    }
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "StandardXYZSolid: {planetmodel="+planetModel+", isWholeWorld="+isWholeWorld+", minXplane="+minXPlane+", maxXplane="+maxXPlane+", minYplane="+minYPlane+", maxYplane="+maxYPlane+", minZplane="+minZPlane+", maxZplane="+maxZPlane+"}";
-  }
-  
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Tools.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Tools.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Tools.java
deleted file mode 100755
index 89d37aa..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Tools.java
+++ /dev/null
@@ -1,41 +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.geo3d;
-
-/**
- * Static methods globally useful for 3d geometric work.
- *
- * @lucene.experimental
- */
-public class Tools {
-  private Tools() {
-  }
-
-  /**
-   * Java acos yields a NAN if you take an arc-cos of an
-   * angle that's just a tiny bit greater than 1.0, so
-   * here's a more resilient version.
-   */
-  public static double safeAcos(double value) {
-    if (value > 1.0)
-      value = 1.0;
-    else if (value < -1.0)
-      value = -1.0;
-    return Math.acos(value);
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Vector.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Vector.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Vector.java
deleted file mode 100755
index 1a3972d..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Vector.java
+++ /dev/null
@@ -1,378 +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.geo3d;
-
-/**
- * A 3d vector in space, not necessarily
- * going through the origin.
- *
- * @lucene.experimental
- */
-public class Vector {
-  /**
-   * Values that are all considered to be essentially zero have a magnitude
-   * less than this.
-   */
-  public static final double MINIMUM_RESOLUTION = 1.0e-12;
-  /**
-   * For squared quantities, the bound is squared too.
-   */
-  public static final double MINIMUM_RESOLUTION_SQUARED = MINIMUM_RESOLUTION * MINIMUM_RESOLUTION;
-  /**
-   * For cubed quantities, cube the bound.
-   */
-  public static final double MINIMUM_RESOLUTION_CUBED = MINIMUM_RESOLUTION_SQUARED * MINIMUM_RESOLUTION;
-
-  /** The x value */
-  public final double x;
-  /** The y value */
-  public final double y;
-  /** The z value */
-  public final double z;
-
-  /**
-   * Construct from (U.S.) x,y,z coordinates.
-   *@param x is the x value.
-   *@param y is the y value.
-   *@param z is the z value.
-   */
-  public Vector(double x, double y, double z) {
-    this.x = x;
-    this.y = y;
-    this.z = z;
-  }
-
-  /**
-   * Construct a vector that is perpendicular to
-   * two other (non-zero) vectors.  If the vectors are parallel,
-   * IllegalArgumentException will be thrown.
-   * Produces a normalized final vector.
-   *
-   * @param A is the first vector
-   * @param B is the second
-   */
-  public Vector(final Vector A, final Vector B) {
-    // x = u2v3 - u3v2
-    // y = u3v1 - u1v3
-    // z = u1v2 - u2v1
-    final double thisX = A.y * B.z - A.z * B.y;
-    final double thisY = A.z * B.x - A.x * B.z;
-    final double thisZ = A.x * B.y - A.y * B.x;
-    final double magnitude = magnitude(thisX, thisY, thisZ);
-    if (Math.abs(magnitude) < MINIMUM_RESOLUTION) {
-      throw new IllegalArgumentException("Degenerate/parallel vector constructed");
-    }
-    final double inverseMagnitude = 1.0 / magnitude;
-    this.x = thisX * inverseMagnitude;
-    this.y = thisY * inverseMagnitude;
-    this.z = thisZ * inverseMagnitude;
-  }
-
-  /** Compute a magnitude of an x,y,z value.
-   */
-  public static double magnitude(final double x, final double y, final double z) {
-    return Math.sqrt(x*x + y*y + z*z);
-  }
-  
-  /**
-   * Compute a normalized unit vector based on the current vector.
-   *
-   * @return the normalized vector, or null if the current vector has
-   * a magnitude of zero.
-   */
-  public Vector normalize() {
-    double denom = magnitude();
-    if (denom < MINIMUM_RESOLUTION)
-      // Degenerate, can't normalize
-      return null;
-    double normFactor = 1.0 / denom;
-    return new Vector(x * normFactor, y * normFactor, z * normFactor);
-  }
-
-  /**
-   * Do a dot product.
-   *
-   * @param v is the vector to multiply.
-   * @return the result.
-   */
-  public double dotProduct(final Vector v) {
-    return this.x * v.x + this.y * v.y + this.z * v.z;
-  }
-
-  /**
-   * Do a dot product.
-   *
-   * @param x is the x value of the vector to multiply.
-   * @param y is the y value of the vector to multiply.
-   * @param z is the z value of the vector to multiply.
-   * @return the result.
-   */
-  public double dotProduct(final double x, final double y, final double z) {
-    return this.x * x + this.y * y + this.z * z;
-  }
-
-  /**
-   * Determine if this vector, taken from the origin,
-   * describes a point within a set of planes.
-   *
-   * @param bounds     is the first part of the set of planes.
-   * @param moreBounds is the second part of the set of planes.
-   * @return true if the point is within the bounds.
-   */
-  public boolean isWithin(final Membership[] bounds, final Membership[] moreBounds) {
-    // Return true if the point described is within all provided bounds
-    //System.err.println("  checking if "+this+" is within bounds");
-    for (Membership bound : bounds) {
-      if (bound != null && !bound.isWithin(this)) {
-        //System.err.println("    NOT within "+bound);
-        return false;
-      }
-    }
-    for (Membership bound : moreBounds) {
-      if (bound != null && !bound.isWithin(this)) {
-        //System.err.println("    NOT within "+bound);
-        return false;
-      }
-    }
-    //System.err.println("    is within");
-    return true;
-  }
-
-  /**
-   * Translate vector.
-   */
-  public Vector translate(final double xOffset, final double yOffset, final double zOffset) {
-    return new Vector(x - xOffset, y - yOffset, z - zOffset);
-  }
-
-  /**
-   * Rotate vector counter-clockwise in x-y by an angle.
-   */
-  public Vector rotateXY(final double angle) {
-    return rotateXY(Math.sin(angle), Math.cos(angle));
-  }
-
-  /**
-   * Rotate vector counter-clockwise in x-y by an angle, expressed as sin and cos.
-   */
-  public Vector rotateXY(final double sinAngle, final double cosAngle) {
-    return new Vector(x * cosAngle - y * sinAngle, x * sinAngle + y * cosAngle, z);
-  }
-
-  /**
-   * Rotate vector counter-clockwise in x-z by an angle.
-   */
-  public Vector rotateXZ(final double angle) {
-    return rotateXZ(Math.sin(angle), Math.cos(angle));
-  }
-
-  /**
-   * Rotate vector counter-clockwise in x-z by an angle, expressed as sin and cos.
-   */
-  public Vector rotateXZ(final double sinAngle, final double cosAngle) {
-    return new Vector(x * cosAngle - z * sinAngle, y, x * sinAngle + z * cosAngle);
-  }
-
-  /**
-   * Rotate vector counter-clockwise in z-y by an angle.
-   */
-  public Vector rotateZY(final double angle) {
-    return rotateZY(Math.sin(angle), Math.cos(angle));
-  }
-
-  /**
-   * Rotate vector counter-clockwise in z-y by an angle, expressed as sin and cos.
-   */
-  public Vector rotateZY(final double sinAngle, final double cosAngle) {
-    return new Vector(x, z * sinAngle + y * cosAngle, z * cosAngle - y * sinAngle);
-  }
-
-  /**
-   * Compute the square of a straight-line distance to a point described by the
-   * vector taken from the origin.
-   * Monotonically increasing for arc distances up to PI.
-   *
-   * @param v is the vector to compute a distance to.
-   * @return the square of the linear distance.
-   */
-  public double linearDistanceSquared(final Vector v) {
-    double deltaX = this.x - v.x;
-    double deltaY = this.y - v.y;
-    double deltaZ = this.z - v.z;
-    return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
-  }
-
-  /**
-   * Compute the square of a straight-line distance to a point described by the
-   * vector taken from the origin.
-   * Monotonically increasing for arc distances up to PI.
-   *
-   * @param x is the x part of the vector to compute a distance to.
-   * @param y is the y part of the vector to compute a distance to.
-   * @param z is the z part of the vector to compute a distance to.
-   * @return the square of the linear distance.
-   */
-  public double linearDistanceSquared(final double x, final double y, final double z) {
-    double deltaX = this.x - x;
-    double deltaY = this.y - y;
-    double deltaZ = this.z - z;
-    return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
-  }
-
-  /**
-   * Compute the straight-line distance to a point described by the
-   * vector taken from the origin.
-   * Monotonically increasing for arc distances up to PI.
-   *
-   * @param v is the vector to compute a distance to.
-   * @return the linear distance.
-   */
-  public double linearDistance(final Vector v) {
-    return Math.sqrt(linearDistanceSquared(v));
-  }
-
-  /**
-   * Compute the straight-line distance to a point described by the
-   * vector taken from the origin.
-   * Monotonically increasing for arc distances up to PI.
-   *
-   * @param x is the x part of the vector to compute a distance to.
-   * @param y is the y part of the vector to compute a distance to.
-   * @param z is the z part of the vector to compute a distance to.
-   * @return the linear distance.
-   */
-  public double linearDistance(final double x, final double y, final double z) {
-    return Math.sqrt(linearDistanceSquared(x, y, z));
-  }
-
-  /**
-   * Compute the square of the normal distance to a vector described by a
-   * vector taken from the origin.
-   * Monotonically increasing for arc distances up to PI/2.
-   *
-   * @param v is the vector to compute a distance to.
-   * @return the square of the normal distance.
-   */
-  public double normalDistanceSquared(final Vector v) {
-    double t = dotProduct(v);
-    double deltaX = this.x * t - v.x;
-    double deltaY = this.y * t - v.y;
-    double deltaZ = this.z * t - v.z;
-    return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
-  }
-
-  /**
-   * Compute the square of the normal distance to a vector described by a
-   * vector taken from the origin.
-   * Monotonically increasing for arc distances up to PI/2.
-   *
-   * @param x is the x part of the vector to compute a distance to.
-   * @param y is the y part of the vector to compute a distance to.
-   * @param z is the z part of the vector to compute a distance to.
-   * @return the square of the normal distance.
-   */
-  public double normalDistanceSquared(final double x, final double y, final double z) {
-    double t = dotProduct(x, y, z);
-    double deltaX = this.x * t - x;
-    double deltaY = this.y * t - y;
-    double deltaZ = this.z * t - z;
-    return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
-  }
-
-  /**
-   * Compute the normal (perpendicular) distance to a vector described by a
-   * vector taken from the origin.
-   * Monotonically increasing for arc distances up to PI/2.
-   *
-   * @param v is the vector to compute a distance to.
-   * @return the normal distance.
-   */
-  public double normalDistance(final Vector v) {
-    return Math.sqrt(normalDistanceSquared(v));
-  }
-
-  /**
-   * Compute the normal (perpendicular) distance to a vector described by a
-   * vector taken from the origin.
-   * Monotonically increasing for arc distances up to PI/2.
-   *
-   * @param x is the x part of the vector to compute a distance to.
-   * @param y is the y part of the vector to compute a distance to.
-   * @param z is the z part of the vector to compute a distance to.
-   * @return the normal distance.
-   */
-  public double normalDistance(final double x, final double y, final double z) {
-    return Math.sqrt(normalDistanceSquared(x, y, z));
-  }
-
-  /**
-   * Compute the magnitude of this vector.
-   *
-   * @return the magnitude.
-   */
-  public double magnitude() {
-    return magnitude(x,y,z);
-  }
-
-  /** Compute the desired magnitude of a unit vector projected to a given
-   * planet model.
-   * @param planetModel is the planet model.
-   * @param x is the unit vector x value.
-   * @param y is the unit vector y value.
-   * @param z is the unit vector z value.
-   * @return a magnitude value for that (x,y,z) that projects the vector onto the specified ellipsoid.
-   */
-  protected static double computeDesiredEllipsoidMagnitude(final PlanetModel planetModel, final double x, final double y, final double z) {
-    return 1.0 / Math.sqrt(x*x*planetModel.inverseAbSquared + y*y*planetModel.inverseAbSquared + z*z*planetModel.inverseCSquared);
-  }
-
-  /** Compute the desired magnitude of a unit vector projected to a given
-   * planet model.  The unit vector is specified only by a z value.
-   * @param planetModel is the planet model.
-   * @param z is the unit vector z value.
-   * @return a magnitude value for that z value that projects the vector onto the specified ellipsoid.
-   */
-  protected static double computeDesiredEllipsoidMagnitude(final PlanetModel planetModel, final double z) {
-    return 1.0 / Math.sqrt((1.0-z*z)*planetModel.inverseAbSquared + z*z*planetModel.inverseCSquared);
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof Vector))
-      return false;
-    Vector other = (Vector) o;
-    return (other.x == x && other.y == y && other.z == z);
-  }
-
-  @Override
-  public int hashCode() {
-    int result;
-    long temp;
-    temp = Double.doubleToLongBits(x);
-    result = (int) (temp ^ (temp >>> 32));
-    temp = Double.doubleToLongBits(y);
-    result = 31 * result + (int) (temp ^ (temp >>> 32));
-    temp = Double.doubleToLongBits(z);
-    result = 31 * result + (int) (temp ^ (temp >>> 32));
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "[X=" + x + ", Y=" + y + ", Z=" + z + "]";
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZBounds.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZBounds.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZBounds.java
deleted file mode 100644
index 22e324b..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZBounds.java
+++ /dev/null
@@ -1,267 +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.geo3d;
-
-/**
- * An object for accumulating XYZ bounds information.
- *
- * @lucene.experimental
- */
-public class XYZBounds implements Bounds {
-
-  /** A 'fudge factor', which is added to maximums and subtracted from minimums,
-   * in order to compensate for potential error deltas.  This would not be necessary
-   * except that our 'bounds' is defined as always equaling or exceeding the boundary
-   * of the shape, and we cannot guarantee that without making MINIMUM_RESOLUTION
-   * unacceptably large.
-   */
-  protected static final double FUDGE_FACTOR = Vector.MINIMUM_RESOLUTION * 2.0;
-  
-  /** Minimum x */
-  protected Double minX = null;
-  /** Maximum x */
-  protected Double maxX = null;
-  /** Minimum y */
-  protected Double minY = null;
-  /** Maximum y */
-  protected Double maxY = null;
-  /** Minimum z */
-  protected Double minZ = null;
-  /** Maximum z */
-  protected Double maxZ = null;
-  
-  /** Set to true if no longitude bounds can be stated */
-  protected boolean noLongitudeBound = false;
-  /** Set to true if no top latitude bound can be stated */
-  protected boolean noTopLatitudeBound = false;
-  /** Set to true if no bottom latitude bound can be stated */
-  protected boolean noBottomLatitudeBound = false;
-
-  /** Construct an empty bounds object */
-  public XYZBounds() {
-  }
-
-  // Accessor methods
-  
-  /** Return the minimum X value.
-   *@return minimum X value.
-   */
-  public Double getMinimumX() {
-    return minX;
-  }
-
-  /** Return the maximum X value.
-   *@return maximum X value.
-   */
-  public Double getMaximumX() {
-    return maxX;
-  }
-
-  /** Return the minimum Y value.
-   *@return minimum Y value.
-   */
-  public Double getMinimumY() {
-    return minY;
-  }
-
-  /** Return the maximum Y value.
-   *@return maximum Y value.
-   */
-  public Double getMaximumY() {
-    return maxY;
-  }
-  
-  /** Return the minimum Z value.
-   *@return minimum Z value.
-   */
-  public Double getMinimumZ() {
-    return minZ;
-  }
-
-  /** Return the maximum Z value.
-   *@return maximum Z value.
-   */
-  public Double getMaximumZ() {
-    return maxZ;
-  }
-
-  /** Return true if minX is as small as the planet model allows.
-   *@return true if minX has reached its bound.
-   */
-  public boolean isSmallestMinX(final PlanetModel planetModel) {
-    if (minX == null)
-      return false;
-    return minX - planetModel.getMinimumXValue() < Vector.MINIMUM_RESOLUTION;
-  }
-  
-  /** Return true if maxX is as large as the planet model allows.
-   *@return true if maxX has reached its bound.
-   */
-  public boolean isLargestMaxX(final PlanetModel planetModel) {
-    if (maxX == null)
-      return false;
-    return planetModel.getMaximumXValue() - maxX < Vector.MINIMUM_RESOLUTION;
-  }
-
-  /** Return true if minY is as small as the planet model allows.
-   *@return true if minY has reached its bound.
-   */
-  public boolean isSmallestMinY(final PlanetModel planetModel) {
-    if (minY == null)
-      return false;
-    return minY - planetModel.getMinimumYValue() < Vector.MINIMUM_RESOLUTION;
-  }
-  
-  /** Return true if maxY is as large as the planet model allows.
-   *@return true if maxY has reached its bound.
-   */
-  public boolean isLargestMaxY(final PlanetModel planetModel) {
-    if (maxY == null)
-      return false;
-    return planetModel.getMaximumYValue() - maxY < Vector.MINIMUM_RESOLUTION;
-  }
-  
-  /** Return true if minZ is as small as the planet model allows.
-   *@return true if minZ has reached its bound.
-   */
-  public boolean isSmallestMinZ(final PlanetModel planetModel) {
-    if (minZ == null)
-      return false;
-    return minZ - planetModel.getMinimumZValue() < Vector.MINIMUM_RESOLUTION;
-  }
-  
-  /** Return true if maxZ is as large as the planet model allows.
-   *@return true if maxZ has reached its bound.
-   */
-  public boolean isLargestMaxZ(final PlanetModel planetModel) {
-    if (maxZ == null)
-      return false;
-    return planetModel.getMaximumZValue() - maxZ < Vector.MINIMUM_RESOLUTION;
-  }
-
-  // Modification methods
-  
-  @Override
-  public Bounds addPlane(final PlanetModel planetModel, final Plane plane, final Membership... bounds) {
-    plane.recordBounds(planetModel, this, bounds);
-    return this;
-  }
-
-  /** Add a horizontal plane to the bounds description.
-   * This method should EITHER use the supplied latitude, OR use the supplied
-   * plane, depending on what is most efficient.
-   *@param planetModel is the planet model.
-   *@param latitude is the latitude.
-   *@param horizontalPlane is the plane.
-   *@param bounds are the constraints on the plane.
-   *@return updated Bounds object.
-   */
-  public Bounds addHorizontalPlane(final PlanetModel planetModel,
-    final double latitude,
-    final Plane horizontalPlane,
-    final Membership... bounds) {
-    return addPlane(planetModel, horizontalPlane, bounds);
-  }
-    
-  /** Add a vertical plane to the bounds description.
-   * This method should EITHER use the supplied longitude, OR use the supplied
-   * plane, depending on what is most efficient.
-   *@param planetModel is the planet model.
-   *@param longitude is the longitude.
-   *@param verticalPlane is the plane.
-   *@param bounds are the constraints on the plane.
-   *@return updated Bounds object.
-   */
-  public Bounds addVerticalPlane(final PlanetModel planetModel,
-    final double longitude,
-    final Plane verticalPlane,
-    final Membership... bounds) {
-    return addPlane(planetModel, verticalPlane, bounds);
-  }
-
-  @Override
-  public Bounds addXValue(final GeoPoint point) {
-    final double x = point.x;
-    final double small = x - FUDGE_FACTOR;
-    if (minX == null || minX > small) {
-      minX = new Double(small);
-    }
-    final double large = x + FUDGE_FACTOR;
-    if (maxX == null || maxX < large) {
-      maxX = new Double(large);
-    }
-    return this;
-  }
-
-  @Override
-  public Bounds addYValue(final GeoPoint point) {
-    final double y = point.y;
-    final double small = y - FUDGE_FACTOR;
-    if (minY == null || minY > small) {
-      minY = new Double(small);
-    }
-    final double large = y + FUDGE_FACTOR;
-    if (maxY == null || maxY < large) {
-      maxY = new Double(large);
-    }
-    return this;
-  }
-
-  @Override
-  public Bounds addZValue(final GeoPoint point) {
-    final double z = point.z;
-    final double small = z - FUDGE_FACTOR;
-    if (minZ == null || minZ > small) {
-      minZ = new Double(small);
-    }
-    final double large = z + FUDGE_FACTOR;
-    if (maxZ == null || maxZ < large) {
-      maxZ = new Double(large);
-    }
-    return this;
-  }
-
-  @Override
-  public Bounds addPoint(final GeoPoint point) {
-    return addXValue(point).addYValue(point).addZValue(point);
-  }
-
-  @Override
-  public Bounds isWide() {
-    // No specific thing we need to do.
-    return this;
-  }
-
-  @Override
-  public Bounds noLongitudeBound() {
-    // No specific thing we need to do.
-    return this;
-  }
-
-  @Override
-  public Bounds noTopLatitudeBound() {
-    // No specific thing we need to do.
-    return this;
-  }
-
-  @Override
-  public Bounds noBottomLatitudeBound() {
-    // No specific thing we need to do.
-    return this;
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolid.java
deleted file mode 100644
index ab46402..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolid.java
+++ /dev/null
@@ -1,26 +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.geo3d;
-
-/**
- * Interface for a family of 3D rectangles, bounded on six sides by X,Y,Z limits
- *
- * @lucene.internal
- */
-public interface XYZSolid extends GeoArea {
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolidFactory.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolidFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolidFactory.java
deleted file mode 100644
index 409ba86..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolidFactory.java
+++ /dev/null
@@ -1,67 +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.geo3d;
-
-/**
- * Factory for {@link org.apache.lucene.geo3d.XYZSolid}.
- *
- * @lucene.experimental
- */
-public class XYZSolidFactory {
-  private XYZSolidFactory() {
-  }
-
-  /**
-   * Create a XYZSolid of the right kind given (x,y,z) bounds.
-   * @param planetModel is the planet model
-   * @param minX is the min X boundary
-   * @param maxX is the max X boundary
-   * @param minY is the min Y boundary
-   * @param maxY is the max Y boundary
-   * @param minZ is the min Z boundary
-   * @param maxZ is the max Z boundary
-   */
-  public static XYZSolid makeXYZSolid(final PlanetModel planetModel, final double minX, final double maxX, final double minY, final double maxY, final double minZ, final double maxZ) {
-    if (Math.abs(maxX - minX) < Vector.MINIMUM_RESOLUTION) {
-      if (Math.abs(maxY - minY) < Vector.MINIMUM_RESOLUTION) {
-        if (Math.abs(maxZ - minZ) < Vector.MINIMUM_RESOLUTION) {
-          return new dXdYdZSolid(planetModel, (minX+maxX) * 0.5, (minY+maxY) * 0.5, minZ);
-        } else {
-          return new dXdYZSolid(planetModel, (minX+maxX) * 0.5, (minY+maxY) * 0.5, minZ, maxZ);
-        }
-      } else {
-        if (Math.abs(maxZ - minZ) < Vector.MINIMUM_RESOLUTION) {
-          return new dXYdZSolid(planetModel, (minX+maxX) * 0.5, minY, maxY, (minZ+maxZ) * 0.5);
-        } else {
-          return new dXYZSolid(planetModel, (minX+maxX) * 0.5, minY, maxY, minZ, maxZ);
-        }
-      }
-    }
-    if (Math.abs(maxY - minY) < Vector.MINIMUM_RESOLUTION) {
-      if (Math.abs(maxZ - minZ) < Vector.MINIMUM_RESOLUTION) {
-        return new XdYdZSolid(planetModel, minX, maxX, (minY+maxY) * 0.5, (minZ+maxZ) * 0.5);
-      } else {
-        return new XdYZSolid(planetModel, minX, maxX, (minY+maxY) * 0.5, minZ, maxZ);
-      }
-    }
-    if (Math.abs(maxZ - minZ) < Vector.MINIMUM_RESOLUTION) {
-      return new XYdZSolid(planetModel, minX, maxX, minY, maxY, (minZ+maxZ) * 0.5);
-    }
-    return new StandardXYZSolid(planetModel, minX, maxX, minY, maxY, minZ, maxZ);
-  }
-  
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYdZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYdZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYdZSolid.java
deleted file mode 100644
index e7cbe25..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYdZSolid.java
+++ /dev/null
@@ -1,213 +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.geo3d;
-
-/**
- * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in Z
- *
- * @lucene.internal
- */
-public class XYdZSolid extends BaseXYZSolid {
-
-  /** Min-X plane */
-  protected final SidedPlane minXPlane;
-  /** Max-X plane */
-  protected final SidedPlane maxXPlane;
-  /** Min-Y plane */
-  protected final SidedPlane minYPlane;
-  /** Max-Y plane */
-  protected final SidedPlane maxYPlane;
-  /** Z plane */
-  protected final Plane zPlane;
-  
-  /** These are the edge points of the shape, which are defined to be at least one point on
-   * each surface area boundary.  In the case of a solid, this includes points which represent
-   * the intersection of XYZ bounding planes and the planet, as well as points representing
-   * the intersection of single bounding planes with the planet itself.
-   */
-  protected final GeoPoint[] edgePoints;
-
-  /** Notable points for ZPlane */
-  protected final GeoPoint[] notableZPoints;
-
-  /**
-   * Sole constructor
-   *
-   *@param planetModel is the planet model.
-   *@param minX is the minimum X value.
-   *@param maxX is the maximum X value.
-   *@param minY is the minimum Y value.
-   *@param maxY is the maximum Y value.
-   *@param Z is the Z value.
-   */
-  public XYdZSolid(final PlanetModel planetModel,
-    final double minX,
-    final double maxX,
-    final double minY,
-    final double maxY,
-    final double Z) {
-    super(planetModel);
-    // Argument checking
-    if (maxX - minX < Vector.MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("X values in wrong order or identical");
-    if (maxY - minY < Vector.MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("Y values in wrong order or identical");
-
-    final double worldMinZ = planetModel.getMinimumZValue();
-    final double worldMaxZ = planetModel.getMaximumZValue();
-    
-    // Construct the planes
-    minXPlane = new SidedPlane(maxX,0.0,0.0,xUnitVector,-minX);
-    maxXPlane = new SidedPlane(minX,0.0,0.0,xUnitVector,-maxX);
-    minYPlane = new SidedPlane(0.0,maxY,0.0,yUnitVector,-minY);
-    maxYPlane = new SidedPlane(0.0,minY,0.0,yUnitVector,-maxY);
-    zPlane = new Plane(zUnitVector,-Z);
-      
-    // We need at least one point on the planet surface for each manifestation of the shape.
-    // There can be up to 2 (on opposite sides of the world).  But we have to go through
-    // 4 combinations of adjacent planes in order to find out if any have 2 intersection solution.
-    // Typically, this requires 4 square root operations. 
-    final GeoPoint[] minXZ = minXPlane.findIntersections(planetModel,zPlane,maxXPlane,minYPlane,maxYPlane);
-    final GeoPoint[] maxXZ = maxXPlane.findIntersections(planetModel,zPlane,minXPlane,minYPlane,maxYPlane);
-    final GeoPoint[] minYZ = minYPlane.findIntersections(planetModel,zPlane,maxYPlane,minXPlane,maxXPlane);
-    final GeoPoint[] maxYZ = maxYPlane.findIntersections(planetModel,zPlane,minYPlane,minXPlane,maxXPlane);
-      
-    notableZPoints = glueTogether(minXZ, maxXZ, minYZ, maxYZ);
-
-    // Now, compute the edge points.
-    // This is the trickiest part of setting up an XYZSolid.  We've computed intersections already, so
-    // we'll start there.  We know that at most there will be two disconnected shapes on the planet surface.
-    // But there's also a case where exactly one plane slices through the world, and none of the bounding plane
-    // intersections do.  Thus, if we don't find any of the edge intersection cases, we have to look for that last case.
-      
-    // If we still haven't encountered anything, we need to look at single-plane/world intersections.
-    // We detect these by looking at the world model and noting its x, y, and z bounds.
-    // The cases we are looking for are when the four corner points for any given
-    // plane are all outside of the world, AND that plane intersects the world.
-    // There are four corner points all told; we must evaluate these WRT the planet surface.
-    final boolean minXminYZ = planetModel.pointOutside(minX, minY, Z);
-    final boolean minXmaxYZ = planetModel.pointOutside(minX, maxY, Z);
-    final boolean maxXminYZ = planetModel.pointOutside(maxX, minY, Z);
-    final boolean maxXmaxYZ = planetModel.pointOutside(maxX, maxY, Z);
-
-    final GeoPoint[] zEdges;
-    if (Z - worldMinZ >= -Vector.MINIMUM_RESOLUTION && Z - worldMaxZ <= Vector.MINIMUM_RESOLUTION &&
-      minX < 0.0 && maxX > 0.0 && minY < 0.0 && maxY > 0.0 &&
-      minXminYZ && minXmaxYZ && maxXminYZ && maxXmaxYZ) {
-      // Find any point on the minZ plane that intersects the world
-      // First construct a perpendicular plane that will allow us to find a sample point.
-      // This plane is vertical and goes through the points (0,0,0) and (1,0,0)
-      // Then use it to compute a sample point.
-      final GeoPoint intPoint = zPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
-      if (intPoint != null) {
-        zEdges = new GeoPoint[]{intPoint};
-      } else {
-        zEdges = EMPTY_POINTS;
-      }
-    } else {
-      zEdges= EMPTY_POINTS;
-    }
-
-    this.edgePoints = glueTogether(minXZ, maxXZ, minYZ, maxYZ, zEdges);
-  }
-
-  @Override
-  protected GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-  
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return minXPlane.isWithin(x, y, z) &&
-      maxXPlane.isWithin(x, y, z) &&
-      minYPlane.isWithin(x, y, z) &&
-      maxYPlane.isWithin(x, y, z) &&
-      zPlane.evaluateIsZero(x, y, z);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    
-    //System.err.println(this+" getrelationship with "+path);
-    final int insideRectangle = isShapeInsideArea(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some inside");
-      return OVERLAPS;
-    }
-
-    // Figure out if the entire XYZArea is contained by the shape.
-    final int insideShape = isAreaInsideShape(path);
-    if (insideShape == SOME_INSIDE) {
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
-      //System.err.println(" inside of each other");
-      return OVERLAPS;
-    }
-
-    if (path.intersects(zPlane, notableZPoints, minXPlane, maxXPlane, minYPlane, maxYPlane)) {
-      //System.err.println(" edges intersect");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      //System.err.println(" shape inside rectangle");
-      return WITHIN;
-    }
-
-    if (insideShape == ALL_INSIDE) {
-      //System.err.println(" shape contains rectangle");
-      return CONTAINS;
-    }
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof XYdZSolid))
-      return false;
-    XYdZSolid other = (XYdZSolid) o;
-    if (!super.equals(other)) {
-      return false;
-    }
-    return other.minXPlane.equals(minXPlane) &&
-      other.maxXPlane.equals(maxXPlane) &&
-      other.minYPlane.equals(minYPlane) &&
-      other.maxYPlane.equals(maxYPlane) &&
-      other.zPlane.equals(zPlane);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result  + minXPlane.hashCode();
-    result = 31 * result  + maxXPlane.hashCode();
-    result = 31 * result  + minYPlane.hashCode();
-    result = 31 * result  + maxYPlane.hashCode();
-    result = 31 * result  + zPlane.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "XYdZSolid: {planetmodel="+planetModel+", minXplane="+minXPlane+", maxXplane="+maxXPlane+", minYplane="+minYPlane+", maxYplane="+maxYPlane+", zplane="+zPlane+"}";
-  }
-  
-}
-  


[31/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 3a31a8c)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoConvexPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoConvexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoConvexPolygon.java
deleted file mode 100755
index fc07c4b..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoConvexPolygon.java
+++ /dev/null
@@ -1,288 +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.geo3d;
-
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.List;
-
-/**
- * GeoConvexPolygon objects are generic building blocks of more complex structures.
- * The only restrictions on these objects are: (1) they must be convex; (2) they must have
- * a maximum extent no larger than PI.  Violating either one of these limits will
- * cause the logic to fail.
- *
- * @lucene.experimental
- */
-public class GeoConvexPolygon extends GeoBasePolygon {
-  /** The list of polygon points */
-  protected final List<GeoPoint> points;
-  /** A bitset describing, for each edge, whether it is internal or not */
-  protected final BitSet isInternalEdges;
-
-  /** A list of edges */
-  protected SidedPlane[] edges = null;
-  /** The set of notable points for each edge */
-  protected GeoPoint[][] notableEdgePoints = null;
-  /** A point which is on the boundary of the polygon */
-  protected GeoPoint[] edgePoints = null;
-  /** Tracking the maximum distance we go at any one time, so to be sure it's legal */
-  protected double fullDistance = 0.0;
-  /** Set to true when the polygon is complete */
-  protected boolean isDone = false;
-  
-  /**
-   * Create a convex polygon from a list of points.  The first point must be on the
-   * external edge.
-   *@param planetModel is the planet model.
-   *@param pointList is the list of points to create the polygon from.
-   */
-  public GeoConvexPolygon(final PlanetModel planetModel, final List<GeoPoint> pointList) {
-    super(planetModel);
-    this.points = pointList;
-    this.isInternalEdges = new BitSet();
-    done(false);
-  }
-
-  /**
-   * Create a convex polygon from a list of points, keeping track of which boundaries
-   * are internal.  This is used when creating a polygon as a building block for another shape.
-   *@param planetModel is the planet model.
-   *@param pointList is the set of points to create the polygon from.
-   *@param internalEdgeFlags is a bitset describing whether each edge is internal or not.
-   *@param returnEdgeInternal is true when the final return edge is an internal one.
-   */
-  public GeoConvexPolygon(final PlanetModel planetModel, final List<GeoPoint> pointList, final BitSet internalEdgeFlags,
-                          final boolean returnEdgeInternal) {
-    super(planetModel);
-    this.points = pointList;
-    this.isInternalEdges = internalEdgeFlags;
-    done(returnEdgeInternal);
-  }
-
-  /**
-   * Create a convex polygon, with a starting latitude and longitude.
-   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
-   *@param planetModel is the planet model.
-   *@param startLatitude is the latitude of the first point.
-   *@param startLongitude is the longitude of the first point.
-   */
-  public GeoConvexPolygon(final PlanetModel planetModel, final double startLatitude, final double startLongitude) {
-    super(planetModel);
-    points = new ArrayList<>();
-    isInternalEdges = new BitSet();
-    points.add(new GeoPoint(planetModel, startLatitude, startLongitude));
-  }
-
-  /**
-   * Add a point to the polygon.
-   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
-   *
-   * @param latitude       is the latitude of the next point.
-   * @param longitude      is the longitude of the next point.
-   * @param isInternalEdge is true if the edge just added with this point should be considered "internal", and not
-   *                       intersected as part of the intersects() operation.
-   */
-  public void addPoint(final double latitude, final double longitude, final boolean isInternalEdge) {
-    if (isDone)
-      throw new IllegalStateException("Can't call addPoint() if done() already called");
-    if (isInternalEdge)
-      isInternalEdges.set(points.size() - 1);
-    points.add(new GeoPoint(planetModel, latitude, longitude));
-  }
-
-  /**
-   * Finish the polygon, by connecting the last added point with the starting point.
-   *@param isInternalReturnEdge is true if the return edge (back to start) is an internal one.
-   */
-  public void done(final boolean isInternalReturnEdge) {
-    if (isDone)
-      throw new IllegalStateException("Can't call done() more than once");
-    // If fewer than 3 points, can't do it.
-    if (points.size() < 3)
-      throw new IllegalArgumentException("Polygon needs at least three points.");
-
-    if (isInternalReturnEdge)
-      isInternalEdges.set(points.size() - 1);
-
-    isDone = true;
-    
-    // Time to construct the planes.  If the polygon is truly convex, then any adjacent point
-    // to a segment can provide an interior measurement.
-    edges = new SidedPlane[points.size()];
-    notableEdgePoints = new GeoPoint[points.size()][];
-
-    for (int i = 0; i < points.size(); i++) {
-      final GeoPoint start = points.get(i);
-      final GeoPoint end = points.get(legalIndex(i + 1));
-      final double distance = start.arcDistance(end);
-      if (distance > fullDistance)
-        fullDistance = distance;
-      final GeoPoint check = points.get(legalIndex(i + 2));
-      final SidedPlane sp = new SidedPlane(check, start, end);
-      //System.out.println("Created edge "+sp+" using start="+start+" end="+end+" check="+check);
-      edges[i] = sp;
-      notableEdgePoints[i] = new GeoPoint[]{start, end};
-    }
-    createCenterPoint();
-  }
-
-  /** Compute a reasonable center point.
-   */
-  protected void createCenterPoint() {
-    // In order to naively confirm that the polygon is convex, I would need to
-    // check every edge, and verify that every point (other than the edge endpoints)
-    // is within the edge's sided plane.  This is an order n^2 operation.  That's still
-    // not wrong, though, because everything else about polygons has a similar cost.
-    for (int edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
-      final SidedPlane edge = edges[edgeIndex];
-      for (int pointIndex = 0; pointIndex < points.size(); pointIndex++) {
-        if (pointIndex != edgeIndex && pointIndex != legalIndex(edgeIndex + 1)) {
-          if (!edge.isWithin(points.get(pointIndex)))
-            throw new IllegalArgumentException("Polygon is not convex: Point " + points.get(pointIndex) + " Edge " + edge);
-        }
-      }
-    }
-    edgePoints = new GeoPoint[]{points.get(0)};
-  }
-
-  /** Compute a legal point index from a possibly illegal one, that may have wrapped.
-   *@param index is the index.
-   *@return the normalized index.
-   */
-  protected int legalIndex(int index) {
-    while (index >= points.size())
-      index -= points.size();
-    return index;
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    for (final SidedPlane edge : edges) {
-      if (!edge.isWithin(x, y, z))
-        return false;
-    }
-    return true;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    //System.err.println("Checking for polygon intersection with plane "+p+"...");
-    for (int edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
-      final SidedPlane edge = edges[edgeIndex];
-      final GeoPoint[] points = this.notableEdgePoints[edgeIndex];
-      if (!isInternalEdges.get(edgeIndex)) {
-        //System.err.println(" non-internal edge "+edge);
-        // Edges flagged as 'internal only' are excluded from the matching
-        // Construct boundaries
-        final Membership[] membershipBounds = new Membership[edges.length - 1];
-        int count = 0;
-        for (int otherIndex = 0; otherIndex < edges.length; otherIndex++) {
-          if (otherIndex != edgeIndex) {
-            membershipBounds[count++] = edges[otherIndex];
-          }
-        }
-        if (edge.intersects(planetModel, p, notablePoints, points, bounds, membershipBounds)) {
-          //System.err.println(" intersects!");
-          return true;
-        }
-      }
-    }
-    //System.err.println(" no intersection");
-    return false;
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-
-    // Add all the points
-    for (final GeoPoint point : points) {
-      bounds.addPoint(point);
-    }
-
-    // Add planes with membership.
-    for (int edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
-      final SidedPlane edge = edges[edgeIndex];
-      // Construct boundaries
-      final Membership[] membershipBounds = new Membership[edges.length - 1];
-      int count = 0;
-      for (int otherIndex = 0; otherIndex < edges.length; otherIndex++) {
-        if (otherIndex != edgeIndex) {
-          membershipBounds[count++] = edges[otherIndex];
-        }
-      }
-      bounds.addPlane(planetModel, edge, membershipBounds);
-    }
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    double minimumDistance = Double.MAX_VALUE;
-    for (final GeoPoint edgePoint : points) {
-      final double newDist = distanceStyle.computeDistance(edgePoint, x,y,z);
-      if (newDist < minimumDistance) {
-        minimumDistance = newDist;
-      }
-    }
-    for (int edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
-      final Plane edgePlane = edges[edgeIndex];
-      final Membership[] membershipBounds = new Membership[edges.length - 1];
-      int count = 0;
-      for (int otherIndex = 0; otherIndex < edges.length; otherIndex++) {
-        if (otherIndex != edgeIndex) {
-          membershipBounds[count++] = edges[otherIndex];
-        }
-      }
-      final double newDist = distanceStyle.computeDistance(planetModel, edgePlane, x, y, z, membershipBounds);
-      if (newDist < minimumDistance) {
-        minimumDistance = newDist;
-      }
-    }
-    return minimumDistance;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoConvexPolygon))
-      return false;
-    GeoConvexPolygon other = (GeoConvexPolygon) o;
-    if (!super.equals(other))
-      return false;
-    if (!other.isInternalEdges.equals(isInternalEdges))
-      return false;
-    return (other.points.equals(points));
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + points.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoConvexPolygon: {planetmodel=" + planetModel + ", points=" + points + "}";
-  }
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateHorizontalLine.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateHorizontalLine.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateHorizontalLine.java
deleted file mode 100644
index 6644f0d..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateHorizontalLine.java
+++ /dev/null
@@ -1,215 +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.geo3d;
-
-/**
- * Degenerate bounding box limited on two sides (left lon, right lon).
- * The left-right maximum extent for this shape is PI; for anything larger, use
- * GeoWideDegenerateHorizontalLine.
- *
- * @lucene.internal
- */
-public class GeoDegenerateHorizontalLine extends GeoBaseBBox {
-  /** Latitude of horizontal line */
-  protected final double latitude;
-  /** Left bounding longitude of line */
-  protected final double leftLon;
-  /** Right bounding longitude of line */
-  protected final double rightLon;
-
-  /** Left hand endpoint of line */
-  protected final GeoPoint LHC;
-  /** Right hand endpoint of line */
-  protected final GeoPoint RHC;
-
-  /** The plane describing the line */
-  protected final Plane plane;
-  /** The left side end plane */
-  protected final SidedPlane leftPlane;
-  /** The right side end plane */
-  protected final SidedPlane rightPlane;
-
-  /** Notable points for the line */
-  protected final GeoPoint[] planePoints;
-
-  /** Center of line */
-  protected final GeoPoint centerPoint;
-  /** A point that's on the line */
-  protected final GeoPoint[] edgePoints;
-
-  /**
-   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
-   *@param planetModel is the planet model.
-   *@param latitude is the latitude of the line.
-   *@param leftLon is the left end longitude.
-   *@param rightLon is the right end longitude.
-   */
-  public GeoDegenerateHorizontalLine(final PlanetModel planetModel, final double latitude, final double leftLon, double rightLon) {
-    super(planetModel);
-    // Argument checking
-    if (latitude > Math.PI * 0.5 || latitude < -Math.PI * 0.5)
-      throw new IllegalArgumentException("Latitude out of range");
-    if (leftLon < -Math.PI || leftLon > Math.PI)
-      throw new IllegalArgumentException("Left longitude out of range");
-    if (rightLon < -Math.PI || rightLon > Math.PI)
-      throw new IllegalArgumentException("Right longitude out of range");
-    double extent = rightLon - leftLon;
-    if (extent < 0.0) {
-      extent += 2.0 * Math.PI;
-    }
-    if (extent > Math.PI)
-      throw new IllegalArgumentException("Width of rectangle too great");
-
-    this.latitude = latitude;
-    this.leftLon = leftLon;
-    this.rightLon = rightLon;
-
-    final double sinLatitude = Math.sin(latitude);
-    final double cosLatitude = Math.cos(latitude);
-    final double sinLeftLon = Math.sin(leftLon);
-    final double cosLeftLon = Math.cos(leftLon);
-    final double sinRightLon = Math.sin(rightLon);
-    final double cosRightLon = Math.cos(rightLon);
-
-    // Now build the two points
-    this.LHC = new GeoPoint(planetModel, sinLatitude, sinLeftLon, cosLatitude, cosLeftLon, latitude, leftLon);
-    this.RHC = new GeoPoint(planetModel, sinLatitude, sinRightLon, cosLatitude, cosRightLon, latitude, rightLon);
-
-    this.plane = new Plane(planetModel, sinLatitude);
-
-    // Normalize
-    while (leftLon > rightLon) {
-      rightLon += Math.PI * 2.0;
-    }
-    final double middleLon = (leftLon + rightLon) * 0.5;
-    final double sinMiddleLon = Math.sin(middleLon);
-    final double cosMiddleLon = Math.cos(middleLon);
-
-    this.centerPoint = new GeoPoint(planetModel, sinLatitude, sinMiddleLon, cosLatitude, cosMiddleLon);
-    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
-    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
-
-    this.planePoints = new GeoPoint[]{LHC, RHC};
-
-    this.edgePoints = new GeoPoint[]{centerPoint};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    double newTopLat = latitude + angle;
-    double newBottomLat = latitude - angle;
-    // Figuring out when we escalate to a special case requires some prefiguring
-    double currentLonSpan = rightLon - leftLon;
-    if (currentLonSpan < 0.0)
-      currentLonSpan += Math.PI * 2.0;
-    double newLeftLon = leftLon - angle;
-    double newRightLon = rightLon + angle;
-    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
-      newLeftLon = -Math.PI;
-      newRightLon = Math.PI;
-    }
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return plane.evaluateIsZero(x, y, z) &&
-        leftPlane.isWithin(x, y, z) &&
-        rightPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public double getRadius() {
-    double topAngle = centerPoint.arcDistance(RHC);
-    double bottomAngle = centerPoint.arcDistance(LHC);
-    return Math.max(topAngle, bottomAngle);
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    return centerPoint;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    return p.intersects(planetModel, plane, notablePoints, planePoints, bounds, leftPlane, rightPlane);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds.addHorizontalPlane(planetModel, latitude, plane, leftPlane, rightPlane)
-      .addPoint(LHC).addPoint(RHC);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    //System.err.println("getting relationship between "+this+" and "+path);
-    if (path.intersects(plane, planePoints, leftPlane, rightPlane)) {
-      //System.err.println(" overlaps");
-      return OVERLAPS;
-    }
-
-    if (path.isWithin(centerPoint)) {
-      //System.err.println(" contains");
-      return CONTAINS;
-    }
-
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    final double distance = distanceStyle.computeDistance(planetModel, plane, x,y,z, leftPlane, rightPlane);
-    
-    final double LHCDistance = distanceStyle.computeDistance(LHC, x,y,z);
-    final double RHCDistance = distanceStyle.computeDistance(RHC, x,y,z);
-    
-    return Math.min(
-      distance,
-      Math.min(LHCDistance, RHCDistance));
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoDegenerateHorizontalLine))
-      return false;
-    GeoDegenerateHorizontalLine other = (GeoDegenerateHorizontalLine) o;
-    return super.equals(other) && other.LHC.equals(LHC) && other.RHC.equals(RHC);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + LHC.hashCode();
-    result = 31 * result + RHC.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoDegenerateHorizontalLine: {planetmodel="+planetModel+", latitude=" + latitude + "(" + latitude * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightLon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
-  }
-}
-  
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateLatitudeZone.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateLatitudeZone.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateLatitudeZone.java
deleted file mode 100644
index 4890733..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateLatitudeZone.java
+++ /dev/null
@@ -1,138 +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.geo3d;
-
-/**
- * This GeoBBox represents an area rectangle of one specific latitude with
- * no longitude bounds.
- *
- * @lucene.internal
- */
-public class GeoDegenerateLatitudeZone extends GeoBaseBBox {
-  /** The latitude */
-  protected final double latitude;
-  /** Sine of the latitude */
-  protected final double sinLatitude;
-  /** Plane describing the latitude zone */
-  protected final Plane plane;
-  /** A point on the world that's also on the zone */
-  protected final GeoPoint interiorPoint;
-  /** An array consisting of the interiorPoint */
-  protected final GeoPoint[] edgePoints;
-  /** No notable points */
-  protected final static GeoPoint[] planePoints = new GeoPoint[0];
-
-  /** Constructor.
-   *@param planetModel is the planet model to use.
-   *@param latitude is the latitude of the latitude zone.
-   */
-  public GeoDegenerateLatitudeZone(final PlanetModel planetModel, final double latitude) {
-    super(planetModel);
-    this.latitude = latitude;
-
-    this.sinLatitude = Math.sin(latitude);
-    double cosLatitude = Math.cos(latitude);
-    this.plane = new Plane(planetModel, sinLatitude);
-    // Compute an interior point.
-    interiorPoint = new GeoPoint(planetModel, sinLatitude, 0.0, cosLatitude, 1.0);
-    edgePoints = new GeoPoint[]{interiorPoint};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    double newTopLat = latitude + angle;
-    double newBottomLat = latitude - angle;
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, -Math.PI, Math.PI);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return Math.abs(z - this.sinLatitude) < 1e-10;
-  }
-
-  @Override
-  public double getRadius() {
-    return Math.PI;
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    // Totally arbitrary
-    return interiorPoint;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    return p.intersects(planetModel, plane, notablePoints, planePoints, bounds);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds.noLongitudeBound()
-      .addHorizontalPlane(planetModel, latitude, plane);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    // Second, the shortcut of seeing whether endpoints are in/out is not going to
-    // work with no area endpoints.  So we rely entirely on intersections.
-    //System.out.println("Got here! latitude="+latitude+" path="+path);
-
-    if (path.intersects(plane, planePoints)) {
-      return OVERLAPS;
-    }
-
-    if (path.isWithin(interiorPoint)) {
-      return CONTAINS;
-    }
-
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    return distanceStyle.computeDistance(planetModel, plane, x,y,z);
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoDegenerateLatitudeZone))
-      return false;
-    GeoDegenerateLatitudeZone other = (GeoDegenerateLatitudeZone) o;
-    return super.equals(other) && other.latitude == latitude;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    long temp = Double.doubleToLongBits(latitude);
-    result = 31 * result + (int) (temp ^ (temp >>> 32));
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoDegenerateLatitudeZone: {planetmodel="+planetModel+", lat=" + latitude + "(" + latitude * 180.0 / Math.PI + ")}";
-  }
-}
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateLongitudeSlice.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateLongitudeSlice.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateLongitudeSlice.java
deleted file mode 100644
index b5eb902..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateLongitudeSlice.java
+++ /dev/null
@@ -1,153 +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.geo3d;
-
-/**
- * Degenerate longitude slice.
- *
- * @lucene.internal
- */
-public class GeoDegenerateLongitudeSlice extends GeoBaseBBox {
-  /** The longitude of the slice */
-  protected final double longitude;
-
-  /** The bounding plane for the slice (through both poles, perpendicular to the slice) */
-  protected final SidedPlane boundingPlane;
-  /** The plane of the slice */
-  protected final Plane plane;
-  /** A point on the slice */
-  protected final GeoPoint interiorPoint;
-  /** An array consisting of the one point chosen on the slice */
-  protected final GeoPoint[] edgePoints;
-  /** Notable points for the slice (north and south poles) */
-  protected final GeoPoint[] planePoints;
-
-  /**
-   * Accepts only values in the following ranges: lon: {@code -PI -> PI}
-   */
-  public GeoDegenerateLongitudeSlice(final PlanetModel planetModel, final double longitude) {
-    super(planetModel);
-    // Argument checking
-    if (longitude < -Math.PI || longitude > Math.PI)
-      throw new IllegalArgumentException("Longitude out of range");
-    this.longitude = longitude;
-
-    final double sinLongitude = Math.sin(longitude);
-    final double cosLongitude = Math.cos(longitude);
-
-    this.plane = new Plane(cosLongitude, sinLongitude);
-    // We need a bounding plane too, which is perpendicular to the longitude plane and sided so that the point (0.0, longitude) is inside.
-    this.interiorPoint = new GeoPoint(planetModel, 0.0, sinLongitude, 1.0, cosLongitude);
-    this.boundingPlane = new SidedPlane(interiorPoint, -sinLongitude, cosLongitude);
-    this.edgePoints = new GeoPoint[]{interiorPoint};
-    this.planePoints = new GeoPoint[]{planetModel.NORTH_POLE, planetModel.SOUTH_POLE};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    // Figuring out when we escalate to a special case requires some prefiguring
-    double newLeftLon = longitude - angle;
-    double newRightLon = longitude + angle;
-    double currentLonSpan = 2.0 * angle;
-    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
-      newLeftLon = -Math.PI;
-      newRightLon = Math.PI;
-    }
-    return GeoBBoxFactory.makeGeoBBox(planetModel, Math.PI * 0.5, -Math.PI * 0.5, newLeftLon, newRightLon);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return plane.evaluateIsZero(x, y, z) &&
-        boundingPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public double getRadius() {
-    return Math.PI * 0.5;
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    return interiorPoint;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    return p.intersects(planetModel, plane, notablePoints, planePoints, bounds, boundingPlane);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds
-      .addVerticalPlane(planetModel, longitude, plane, boundingPlane)
-      .addPoint(planetModel.NORTH_POLE).addPoint(planetModel.SOUTH_POLE);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    // Look for intersections.
-    if (path.intersects(plane, planePoints, boundingPlane))
-      return OVERLAPS;
-
-    if (path.isWithin(interiorPoint))
-      return CONTAINS;
-
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    final double distance = distanceStyle.computeDistance(planetModel, plane, x,y,z, boundingPlane);
-    
-    final double northDistance = distanceStyle.computeDistance(planetModel.NORTH_POLE, x,y,z);
-    final double southDistance = distanceStyle.computeDistance(planetModel.SOUTH_POLE, x,y,z);
-    
-    return Math.min(
-      distance,
-      Math.min(northDistance, southDistance));
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoDegenerateLongitudeSlice))
-      return false;
-    GeoDegenerateLongitudeSlice other = (GeoDegenerateLongitudeSlice) o;
-    return super.equals(other) && other.longitude == longitude;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    long temp = Double.doubleToLongBits(longitude);
-    result = result * 31 + (int) (temp ^ (temp >>> 32));
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoDegenerateLongitudeSlice: {planetmodel="+planetModel+", longitude=" + longitude + "(" + longitude * 180.0 / Math.PI + ")}";
-  }
-}
-  
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegeneratePoint.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegeneratePoint.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegeneratePoint.java
deleted file mode 100644
index 63670d7..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegeneratePoint.java
+++ /dev/null
@@ -1,135 +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.geo3d;
-    
-/**
- * This class represents a degenerate point bounding box.
- * It is not a simple GeoPoint because we must have the latitude and longitude.
- *
- * @lucene.internal
- */
-public class GeoDegeneratePoint extends GeoPoint implements GeoBBox, GeoCircle {
-  /** Current planet model, since we don't extend BasePlanetObject */
-  protected final PlanetModel planetModel;
-  /** Edge point is an area containing just this */
-  protected final GeoPoint[] edgePoints;
-
-  /** Constructor.
-   *@param planetModel is the planet model to use.
-   *@param lat is the latitude.
-   *@param lon is the longitude.
-   */
-  public GeoDegeneratePoint(final PlanetModel planetModel, final double lat, final double lon) {
-    super(planetModel, lat, lon);
-    this.planetModel = planetModel;
-    this.edgePoints = new GeoPoint[]{this};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    final double newTopLat = latitude + angle;
-    final double newBottomLat = latitude - angle;
-    final double newLeftLon = longitude - angle;
-    final double newRightLon = longitude + angle;
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane plane, final GeoPoint[] notablePoints, final Membership... bounds) {
-    // If not on the plane, no intersection
-    if (!plane.evaluateIsZero(this))
-      return false;
-
-    for (Membership m : bounds) {
-      if (!m.isWithin(this))
-        return false;
-    }
-    return true;
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    bounds.addPoint(this);
-  }
-
-  @Override
-  public double computeOutsideDistance(final DistanceStyle distanceStyle, final GeoPoint point) {
-    return distanceStyle.computeDistance(this, point);
-  }
-
-  @Override
-  public double computeOutsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    return distanceStyle.computeDistance(this, x,y,z);
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoDegeneratePoint))
-      return false;
-    GeoDegeneratePoint other = (GeoDegeneratePoint) o;
-    return super.equals(other) && other.latitude == latitude && other.longitude == longitude;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoDegeneratePoint: {planetmodel="+planetModel+", lat=" + latitude + "(" + latitude * 180.0 / Math.PI + "), lon=" + longitude + "(" + longitude * 180.0 / Math.PI + ")}";
-  }
-
-  @Override
-  public boolean isWithin(final Vector point) {
-    return isWithin(point.x, point.y, point.z);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return x == this.x && y == this.y && z == this.z;
-  }
-
-  @Override
-  public double getRadius() {
-    return 0.0;
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    return this;
-  }
-
-  @Override
-  public int getRelationship(final GeoShape shape) {
-    if (shape.isWithin(this)) {
-      //System.err.println("Degenerate point "+this+" is WITHIN shape "+shape);
-      return CONTAINS;
-    }
-
-    //System.err.println("Degenerate point "+this+" is NOT within shape "+shape);
-    return DISJOINT;
-  }
-
-  @Override
-  public double computeDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    if (isWithin(x,y,z))
-      return 0.0;
-    return Double.MAX_VALUE;
-  }
-}
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateVerticalLine.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateVerticalLine.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateVerticalLine.java
deleted file mode 100644
index f21f774..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateVerticalLine.java
+++ /dev/null
@@ -1,205 +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.geo3d;
-
-/**
- * Degenerate bounding box limited on two sides (top lat, bottom lat).
- *
- * @lucene.internal
- */
-public class GeoDegenerateVerticalLine extends GeoBaseBBox {
-  /** Top latitude of the vertical line */
-  protected final double topLat;
-  /** Bottom latitude of the vertical line */
-  protected final double bottomLat;
-  /** Longitude of the vertical line */
-  protected final double longitude;
-
-  /** Point at the upper end of the vertical line */
-  protected final GeoPoint UHC;
-  /** Point at the lower end of the vertical line */
-  protected final GeoPoint LHC;
-
-  /** Top end cutoff plane */
-  protected final SidedPlane topPlane;
-  /** Bottom end cutoff plane */
-  protected final SidedPlane bottomPlane;
-  /** Back-side cutoff plane */
-  protected final SidedPlane boundingPlane;
-  /** The vertical line plane */
-  protected final Plane plane;
-  /** Notable points for the line (end points) */
-  protected final GeoPoint[] planePoints;
-  /** A computed center point for the line */
-  protected final GeoPoint centerPoint;
-  /** A point that's on the line */
-  protected final GeoPoint[] edgePoints;
-
-  /**
-   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, longitude: {@code -PI -> PI}
-   */
-  public GeoDegenerateVerticalLine(final PlanetModel planetModel, final double topLat, final double bottomLat, final double longitude) {
-    super(planetModel);
-    // Argument checking
-    if (topLat > Math.PI * 0.5 || topLat < -Math.PI * 0.5)
-      throw new IllegalArgumentException("Top latitude out of range");
-    if (bottomLat > Math.PI * 0.5 || bottomLat < -Math.PI * 0.5)
-      throw new IllegalArgumentException("Bottom latitude out of range");
-    if (topLat < bottomLat)
-      throw new IllegalArgumentException("Top latitude less than bottom latitude");
-    if (longitude < -Math.PI || longitude > Math.PI)
-      throw new IllegalArgumentException("Longitude out of range");
-
-    this.topLat = topLat;
-    this.bottomLat = bottomLat;
-    this.longitude = longitude;
-
-    final double sinTopLat = Math.sin(topLat);
-    final double cosTopLat = Math.cos(topLat);
-    final double sinBottomLat = Math.sin(bottomLat);
-    final double cosBottomLat = Math.cos(bottomLat);
-    final double sinLongitude = Math.sin(longitude);
-    final double cosLongitude = Math.cos(longitude);
-
-    // Now build the two points
-    this.UHC = new GeoPoint(planetModel, sinTopLat, sinLongitude, cosTopLat, cosLongitude, topLat, longitude);
-    this.LHC = new GeoPoint(planetModel, sinBottomLat, sinLongitude, cosBottomLat, cosLongitude, bottomLat, longitude);
-
-    this.plane = new Plane(cosLongitude, sinLongitude);
-
-    final double middleLat = (topLat + bottomLat) * 0.5;
-    final double sinMiddleLat = Math.sin(middleLat);
-    final double cosMiddleLat = Math.cos(middleLat);
-
-    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinLongitude, cosMiddleLat, cosLongitude);
-
-    this.topPlane = new SidedPlane(centerPoint, planetModel, sinTopLat);
-    this.bottomPlane = new SidedPlane(centerPoint, planetModel, sinBottomLat);
-
-    this.boundingPlane = new SidedPlane(centerPoint, -sinLongitude, cosLongitude);
-
-    this.planePoints = new GeoPoint[]{UHC, LHC};
-
-    this.edgePoints = new GeoPoint[]{centerPoint};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    final double newTopLat = topLat + angle;
-    final double newBottomLat = bottomLat - angle;
-    double newLeftLon = longitude - angle;
-    double newRightLon = longitude + angle;
-    double currentLonSpan = 2.0 * angle;
-    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
-      newLeftLon = -Math.PI;
-      newRightLon = Math.PI;
-    }
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return plane.evaluateIsZero(x, y, z) &&
-        boundingPlane.isWithin(x, y, z) &&
-        topPlane.isWithin(x, y, z) &&
-        bottomPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public double getRadius() {
-    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
-    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
-    // the distance to the right or left edge from the center.
-    final double topAngle = centerPoint.arcDistance(UHC);
-    final double bottomAngle = centerPoint.arcDistance(LHC);
-    return Math.max(topAngle, bottomAngle);
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    return centerPoint;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    return p.intersects(planetModel, plane, notablePoints, planePoints, bounds, boundingPlane, topPlane, bottomPlane);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds.addVerticalPlane(planetModel, longitude, plane, boundingPlane, topPlane, bottomPlane)
-      .addPoint(UHC).addPoint(LHC);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    //System.err.println(this+" relationship to "+path);
-    if (path.intersects(plane, planePoints, boundingPlane, topPlane, bottomPlane)) {
-      //System.err.println(" overlaps");
-      return OVERLAPS;
-    }
-
-    if (path.isWithin(centerPoint)) {
-      //System.err.println(" contains");
-      return CONTAINS;
-    }
-
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    final double distance = distanceStyle.computeDistance(planetModel, plane, x,y,z, topPlane, bottomPlane, boundingPlane);
-    
-    final double UHCDistance = distanceStyle.computeDistance(UHC, x,y,z);
-    final double LHCDistance = distanceStyle.computeDistance(LHC, x,y,z);
-    
-    return Math.min(
-      distance,
-      Math.min(UHCDistance, LHCDistance));
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoDegenerateVerticalLine))
-      return false;
-    GeoDegenerateVerticalLine other = (GeoDegenerateVerticalLine) o;
-    return super.equals(other) && other.UHC.equals(UHC) && other.LHC.equals(LHC);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + UHC.hashCode();
-    result = 31 * result + LHC.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoDegenerateVerticalLine: {longitude=" + longitude + "(" + longitude * 180.0 / Math.PI + "), toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + "), bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + ")}";
-  }
-}
-  
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDistance.java
deleted file mode 100755
index 899a687..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDistance.java
+++ /dev/null
@@ -1,59 +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.geo3d;
-
-/**
- * An implementer of this interface is capable of computing the described "distance" values,
- * which are meant to provide both actual distance values, as well as
- * distance estimates that can be computed more cheaply.
- *
- * @lucene.experimental
- */
-public interface GeoDistance extends Membership {
-  
-  // The following methods compute distances from the shape to a point
-  // expected to be INSIDE the shape.  Typically a value of Double.MAX_VALUE
-  // is returned for points that happen to be outside the shape.
-
-  /**
-   * Compute this shape's <em>internal</em> "distance" to the GeoPoint.
-   * Implementations should clarify how this is computed when it's non-obvious.
-   * A return value of Double.MAX_VALUE should be returned for
-   * points outside of the shape.
-   *
-   * @param distanceStyle is the distance style.
-   * @param point is the point to compute the distance to.
-   * @return the distance.
-   */
-  public default double computeDistance(final DistanceStyle distanceStyle, final GeoPoint point) {
-    return computeDistance(distanceStyle, point.x, point.y, point.z);
-  }
-
-  /**
-   * Compute this shape's <em>internal</em> "distance" to the GeoPoint.
-   * Implementations should clarify how this is computed when it's non-obvious.
-   * A return value of Double.MAX_VALUE should be returned for
-   * points outside of the shape.
-   *
-   * @param x is the point's unit x coordinate (using U.S. convention).
-   * @param y is the point's unit y coordinate (using U.S. convention).
-   * @param z is the point's unit z coordinate (using U.S. convention).
-   * @return the distance.
-   */
-  public double computeDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z);
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDistanceShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDistanceShape.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDistanceShape.java
deleted file mode 100755
index 1e82f48..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDistanceShape.java
+++ /dev/null
@@ -1,27 +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.geo3d;
-
-/**
- * Distance shapes have capabilities of both geohashing and distance
- * computation (which also includes point membership determination).
- *
- * @lucene.experimental
- */
-public interface GeoDistanceShape extends GeoMembershipShape, GeoDistance {
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoLatitudeZone.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoLatitudeZone.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoLatitudeZone.java
deleted file mode 100755
index 3fc4423..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoLatitudeZone.java
+++ /dev/null
@@ -1,198 +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.geo3d;
-
-/**
- * This GeoBBox represents an area rectangle limited only in latitude.
- *
- * @lucene.internal
- */
-public class GeoLatitudeZone extends GeoBaseBBox {
-  /** The top latitude of the zone */
-  protected final double topLat;
-  /** The bottom latitude of the zone */
-  protected final double bottomLat;
-  /** Cosine of the top lat */
-  protected final double cosTopLat;
-  /** Cosine of the bottom lat */
-  protected final double cosBottomLat;
-  /** The top plane */
-  protected final SidedPlane topPlane;
-  /** The bottom plane */
-  protected final SidedPlane bottomPlane;
-  /** An interior point */
-  protected final GeoPoint interiorPoint;
-  /** Notable points (none) */
-  protected final static GeoPoint[] planePoints = new GeoPoint[0];
-
-  // We need two additional points because a latitude zone's boundaries don't intersect.  This is a very
-  // special case that most GeoBBox's do not have.
-  
-  /** Top boundary point */
-  protected final GeoPoint topBoundaryPoint;
-  /** Bottom boundary point */
-  protected final GeoPoint bottomBoundaryPoint;
-  /** A point on each distinct edge */
-  protected final GeoPoint[] edgePoints;
-
-  /** Constructor.
-   *@param planetModel is the planet model to use.
-   *@param topLat is the top latitude.
-   *@param bottomLat is the bottom latitude.
-   */
-  public GeoLatitudeZone(final PlanetModel planetModel, final double topLat, final double bottomLat) {
-    super(planetModel);
-    this.topLat = topLat;
-    this.bottomLat = bottomLat;
-
-    final double sinTopLat = Math.sin(topLat);
-    final double sinBottomLat = Math.sin(bottomLat);
-    this.cosTopLat = Math.cos(topLat);
-    this.cosBottomLat = Math.cos(bottomLat);
-
-    // Compute an interior point.  Pick one whose lat is between top and bottom.
-    final double middleLat = (topLat + bottomLat) * 0.5;
-    final double sinMiddleLat = Math.sin(middleLat);
-    this.interiorPoint = new GeoPoint(planetModel, sinMiddleLat, 0.0, Math.sqrt(1.0 - sinMiddleLat * sinMiddleLat), 1.0);
-    this.topBoundaryPoint = new GeoPoint(planetModel, sinTopLat, 0.0, Math.sqrt(1.0 - sinTopLat * sinTopLat), 1.0);
-    this.bottomBoundaryPoint = new GeoPoint(planetModel, sinBottomLat, 0.0, Math.sqrt(1.0 - sinBottomLat * sinBottomLat), 1.0);
-
-    this.topPlane = new SidedPlane(interiorPoint, planetModel, sinTopLat);
-    this.bottomPlane = new SidedPlane(interiorPoint, planetModel, sinBottomLat);
-
-    this.edgePoints = new GeoPoint[]{topBoundaryPoint, bottomBoundaryPoint};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    final double newTopLat = topLat + angle;
-    final double newBottomLat = bottomLat - angle;
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, -Math.PI, Math.PI);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return topPlane.isWithin(x, y, z) &&
-        bottomPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public double getRadius() {
-    // This is a bit tricky.  I guess we should interpret this as meaning the angle of a circle that
-    // would contain all the bounding box points, when starting in the "center".
-    if (topLat > 0.0 && bottomLat < 0.0)
-      return Math.PI;
-    double maxCosLat = cosTopLat;
-    if (maxCosLat < cosBottomLat)
-      maxCosLat = cosBottomLat;
-    return maxCosLat * Math.PI;
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    // This is totally arbitrary and only a cartesian could agree with it.
-    return interiorPoint;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    return p.intersects(planetModel, topPlane, notablePoints, planePoints, bounds, bottomPlane) ||
-        p.intersects(planetModel, bottomPlane, notablePoints, planePoints, bounds, topPlane);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds.noLongitudeBound()
-      .addHorizontalPlane(planetModel, topLat, topPlane)
-      .addHorizontalPlane(planetModel, bottomLat, bottomPlane);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    final int insideRectangle = isShapeInsideBBox(path);
-    if (insideRectangle == SOME_INSIDE)
-      return OVERLAPS;
-
-    final boolean topBoundaryInsideShape = path.isWithin(topBoundaryPoint);
-    final boolean bottomBoundaryInsideShape = path.isWithin(bottomBoundaryPoint);
-
-    if (topBoundaryInsideShape && !bottomBoundaryInsideShape ||
-        !topBoundaryInsideShape && bottomBoundaryInsideShape)
-      return OVERLAPS;
-
-    final boolean insideShape = topBoundaryInsideShape && bottomBoundaryInsideShape;
-
-    if (insideRectangle == ALL_INSIDE && insideShape)
-      return OVERLAPS;
-
-    // Second, the shortcut of seeing whether endpoints are in/out is not going to
-    // work with no area endpoints.  So we rely entirely on intersections.
-
-    if (path.intersects(topPlane, planePoints, bottomPlane) ||
-        path.intersects(bottomPlane, planePoints, topPlane))
-      return OVERLAPS;
-
-    // There is another case for latitude zones only.  This is when the boundaries of the shape all fit
-    // within the zone, but the shape includes areas outside the zone crossing a pole.
-    // In this case, the above "overlaps" check is insufficient.  We also need to check a point on either boundary
-    // whether it is within the shape.  If both such points are within, then CONTAINS is the right answer.  If
-    // one such point is within, then OVERLAPS is the right answer.
-
-    if (insideShape)
-      return CONTAINS;
-
-    if (insideRectangle == ALL_INSIDE)
-      return WITHIN;
-
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    final double topDistance = distanceStyle.computeDistance(planetModel, topPlane, x,y,z, bottomPlane);
-    final double bottomDistance = distanceStyle.computeDistance(planetModel, bottomPlane, x,y,z, topPlane);
-
-    return Math.min(topDistance, bottomDistance);
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoLatitudeZone))
-      return false;
-    GeoLatitudeZone other = (GeoLatitudeZone) o;
-    return super.equals(other) && other.topBoundaryPoint.equals(topBoundaryPoint) && other.bottomBoundaryPoint.equals(bottomBoundaryPoint);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + topBoundaryPoint.hashCode();
-    result = 31 * result + bottomBoundaryPoint.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoLatitudeZone: {planetmodel="+planetModel+", toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + "), bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + ")}";
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoLongitudeSlice.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoLongitudeSlice.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoLongitudeSlice.java
deleted file mode 100755
index f5de7e7..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoLongitudeSlice.java
+++ /dev/null
@@ -1,204 +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.geo3d;
-
-/**
- * Bounding box limited on left and right.
- * The left-right maximum extent for this shape is PI; for anything larger, use
- * {@link GeoWideLongitudeSlice}.
- *
- * @lucene.internal
- */
-public class GeoLongitudeSlice extends GeoBaseBBox {
-  /** The left longitude of the slice */
-  protected final double leftLon;
-  /** The right longitude of the slice */
-  protected final double rightLon;
-  /** The left plane of the slice */
-  protected final SidedPlane leftPlane;
-  /** The right plane of the slice */
-  protected final SidedPlane rightPlane;
-  /** The notable points for the slice (north and south poles) */
-  protected final GeoPoint[] planePoints;
-  /** The center point of the slice */
-  protected final GeoPoint centerPoint;
-  /** A point on the edge of the slice */
-  protected final GeoPoint[] edgePoints;
-
-  /**
-   * Accepts only values in the following ranges: lon: {@code -PI -> PI}
-   *@param planetModel is the planet model.
-   *@param leftLon is the left longitude of the slice.
-   *@param rightLon is the right longitude of the slice.
-   */
-  public GeoLongitudeSlice(final PlanetModel planetModel, final double leftLon, double rightLon) {
-    super(planetModel);
-    // Argument checking
-    if (leftLon < -Math.PI || leftLon > Math.PI)
-      throw new IllegalArgumentException("Left longitude out of range");
-    if (rightLon < -Math.PI || rightLon > Math.PI)
-      throw new IllegalArgumentException("Right longitude out of range");
-    double extent = rightLon - leftLon;
-    if (extent < 0.0) {
-      extent += 2.0 * Math.PI;
-    }
-    if (extent > Math.PI)
-      throw new IllegalArgumentException("Width of rectangle too great");
-
-    this.leftLon = leftLon;
-    this.rightLon = rightLon;
-
-    final double sinLeftLon = Math.sin(leftLon);
-    final double cosLeftLon = Math.cos(leftLon);
-    final double sinRightLon = Math.sin(rightLon);
-    final double cosRightLon = Math.cos(rightLon);
-
-    // Normalize
-    while (leftLon > rightLon) {
-      rightLon += Math.PI * 2.0;
-    }
-    final double middleLon = (leftLon + rightLon) * 0.5;
-    this.centerPoint = new GeoPoint(planetModel, 0.0, middleLon);
-
-    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
-    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
-
-    this.planePoints = new GeoPoint[]{planetModel.NORTH_POLE, planetModel.SOUTH_POLE};
-    this.edgePoints = new GeoPoint[]{planetModel.NORTH_POLE};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    // Figuring out when we escalate to a special case requires some prefiguring
-    double currentLonSpan = rightLon - leftLon;
-    if (currentLonSpan < 0.0)
-      currentLonSpan += Math.PI * 2.0;
-    double newLeftLon = leftLon - angle;
-    double newRightLon = rightLon + angle;
-    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
-      newLeftLon = -Math.PI;
-      newRightLon = Math.PI;
-    }
-    return GeoBBoxFactory.makeGeoBBox(planetModel, Math.PI * 0.5, -Math.PI * 0.5, newLeftLon, newRightLon);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return leftPlane.isWithin(x, y, z) &&
-        rightPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public double getRadius() {
-    // Compute the extent and divide by two
-    double extent = rightLon - leftLon;
-    if (extent < 0.0)
-      extent += Math.PI * 2.0;
-    return Math.max(Math.PI * 0.5, extent * 0.5);
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    return centerPoint;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    return p.intersects(planetModel, leftPlane, notablePoints, planePoints, bounds, rightPlane) ||
-        p.intersects(planetModel, rightPlane, notablePoints, planePoints, bounds, leftPlane);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds
-      .addVerticalPlane(planetModel, leftLon, leftPlane, rightPlane)
-      .addVerticalPlane(planetModel, rightLon, rightPlane, leftPlane)
-      .addPoint(planetModel.NORTH_POLE)
-      .addPoint(planetModel.SOUTH_POLE);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    final int insideRectangle = isShapeInsideBBox(path);
-    if (insideRectangle == SOME_INSIDE)
-      return OVERLAPS;
-
-    final boolean insideShape = path.isWithin(planetModel.NORTH_POLE);
-
-    if (insideRectangle == ALL_INSIDE && insideShape)
-      return OVERLAPS;
-
-    if (path.intersects(leftPlane, planePoints, rightPlane) ||
-        path.intersects(rightPlane, planePoints, leftPlane)) {
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      return WITHIN;
-    }
-
-    if (insideShape) {
-      return CONTAINS;
-    }
-
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, rightPlane);
-    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, leftPlane);
-    
-    final double northDistance = distanceStyle.computeDistance(planetModel.NORTH_POLE, x,y,z);
-    final double southDistance = distanceStyle.computeDistance(planetModel.SOUTH_POLE, x,y,z);
-    
-    return
-      Math.min(
-        Math.min(northDistance, southDistance),
-        Math.min(leftDistance, rightDistance));
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoLongitudeSlice))
-      return false;
-    GeoLongitudeSlice other = (GeoLongitudeSlice) o;
-    return super.equals(other) && other.leftLon == leftLon && other.rightLon == rightLon;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    long temp = Double.doubleToLongBits(leftLon);
-    result = 31 * result + (int) (temp ^ (temp >>> 32));
-    temp = Double.doubleToLongBits(rightLon);
-    result = 31 * result + (int) (temp ^ (temp >>> 32));
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoLongitudeSlice: {planetmodel="+planetModel+", leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
-  }
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoMembershipShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoMembershipShape.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoMembershipShape.java
deleted file mode 100755
index 54b2551..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoMembershipShape.java
+++ /dev/null
@@ -1,27 +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.geo3d;
-
-/**
- * Membership shapes have capabilities of both geohashing and membership
- * determination.
- *
- * @lucene.experimental
- */
-public interface GeoMembershipShape extends GeoShape, GeoOutsideDistance, Membership {
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoNorthLatitudeZone.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoNorthLatitudeZone.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoNorthLatitudeZone.java
deleted file mode 100644
index 43338bb..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoNorthLatitudeZone.java
+++ /dev/null
@@ -1,165 +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.geo3d;
-
-/**
- * This GeoBBox represents an area rectangle limited only in south latitude.
- *
- * @lucene.internal
- */
-public class GeoNorthLatitudeZone extends GeoBaseBBox {
-  /** The bottom latitude of the zone */
-  protected final double bottomLat;
-  /** Cosine of the bottom latitude of the zone */
-  protected final double cosBottomLat;
-  /** The bottom plane of the zone */
-  protected final SidedPlane bottomPlane;
-  /** An interior point of the zone */
-  protected final GeoPoint interiorPoint;
-  /** Notable points: none */
-  protected final static GeoPoint[] planePoints = new GeoPoint[0];
-  /** A point on the bottom boundary */
-  protected final GeoPoint bottomBoundaryPoint;
-  /** A reference to the point on the boundary */
-  protected final GeoPoint[] edgePoints;
-
-  /** Constructor.
-   *@param planetModel is the planet model.
-   *@param bottomLat is the bottom latitude.
-   */
-  public GeoNorthLatitudeZone(final PlanetModel planetModel, final double bottomLat) {
-    super(planetModel);
-    this.bottomLat = bottomLat;
-
-    final double sinBottomLat = Math.sin(bottomLat);
-    this.cosBottomLat = Math.cos(bottomLat);
-
-    // Compute an interior point.  Pick one whose lat is between top and bottom.
-    final double middleLat = (Math.PI * 0.5 + bottomLat) * 0.5;
-    final double sinMiddleLat = Math.sin(middleLat);
-    this.interiorPoint = new GeoPoint(planetModel, sinMiddleLat, 0.0, Math.sqrt(1.0 - sinMiddleLat * sinMiddleLat), 1.0);
-    this.bottomBoundaryPoint = new GeoPoint(planetModel, sinBottomLat, 0.0, Math.sqrt(1.0 - sinBottomLat * sinBottomLat), 1.0);
-
-    this.bottomPlane = new SidedPlane(interiorPoint, planetModel, sinBottomLat);
-
-    this.edgePoints = new GeoPoint[]{bottomBoundaryPoint};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    final double newTopLat = Math.PI * 0.5;
-    final double newBottomLat = bottomLat - angle;
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, -Math.PI, Math.PI);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return
-        bottomPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public double getRadius() {
-    // This is a bit tricky.  I guess we should interpret this as meaning the angle of a circle that
-    // would contain all the bounding box points, when starting in the "center".
-    if (bottomLat < 0.0)
-      return Math.PI;
-    double maxCosLat = cosBottomLat;
-    return maxCosLat * Math.PI;
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    return interiorPoint;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    return
-        p.intersects(planetModel, bottomPlane, notablePoints, planePoints, bounds);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds
-      .addHorizontalPlane(planetModel, bottomLat, bottomPlane);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    final int insideRectangle = isShapeInsideBBox(path);
-    if (insideRectangle == SOME_INSIDE)
-      return OVERLAPS;
-
-    final boolean insideShape = path.isWithin(bottomBoundaryPoint);
-
-    if (insideRectangle == ALL_INSIDE && insideShape)
-      return OVERLAPS;
-
-    // Second, the shortcut of seeing whether endpoints are in/out is not going to
-    // work with no area endpoints.  So we rely entirely on intersections.
-
-    if (path.intersects(bottomPlane, planePoints))
-      return OVERLAPS;
-
-    // There is another case for latitude zones only.  This is when the boundaries of the shape all fit
-    // within the zone, but the shape includes areas outside the zone crossing a pole.
-    // In this case, the above "overlaps" check is insufficient.  We also need to check a point on either boundary
-    // whether it is within the shape.  If both such points are within, then CONTAINS is the right answer.  If
-    // one such point is within, then OVERLAPS is the right answer.
-
-    if (insideShape)
-      return CONTAINS;
-
-    if (insideRectangle == ALL_INSIDE)
-      return WITHIN;
-
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    return distanceStyle.computeDistance(planetModel, bottomPlane, x,y,z);
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoNorthLatitudeZone))
-      return false;
-    GeoNorthLatitudeZone other = (GeoNorthLatitudeZone) o;
-    return super.equals(other) && other.bottomBoundaryPoint.equals(bottomBoundaryPoint);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + bottomBoundaryPoint.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoNorthLatitudeZone: {planetmodel="+planetModel+", bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + ")}";
-  }
-}
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoNorthRectangle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoNorthRectangle.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoNorthRectangle.java
deleted file mode 100644
index 66b9480..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoNorthRectangle.java
+++ /dev/null
@@ -1,263 +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.geo3d;
-
-/**
- * Bounding box limited on three sides (bottom lat, left lon, right lon), including
- * the north pole.
- * The left-right maximum extent for this shape is PI; for anything larger, use
- * {@link GeoWideNorthRectangle}.
- *
- * @lucene.internal
- */
-public class GeoNorthRectangle extends GeoBaseBBox {
-  /** The bottom latitude of the rectangle */
-  protected final double bottomLat;
-  /** The left longitude */
-  protected final double leftLon;
-  /** The right longitude */
-  protected final double rightLon;
-  /** Cosine of the middle latitude */
-  protected final double cosMiddleLat;
-  /** Lower right hand corner point */
-  protected final GeoPoint LRHC;
-  /** Lower left hand corner point */
-  protected final GeoPoint LLHC;
-  /** Bottom edge plane */
-  protected final SidedPlane bottomPlane;
-  /** Left-side plane */
-  protected final SidedPlane leftPlane;
-  /** Right-side plane */
-  protected final SidedPlane rightPlane;
-  /** Bottom plane notable points */
-  protected final GeoPoint[] bottomPlanePoints;
-  /** Left plane notable points */
-  protected final GeoPoint[] leftPlanePoints;
-  /** Right plane notable points */
-  protected final GeoPoint[] rightPlanePoints;
-  /** Center point */
-  protected final GeoPoint centerPoint;
-  /** A point on the edge */
-  protected final GeoPoint[] edgePoints;
-
-  /**
-   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
-   *@param planetModel is the planet model.
-   *@param bottomLat is the bottom latitude.
-   *@param leftLon is the left longitude.
-   *@param rightLon is the right longitude.
-   */
-  public GeoNorthRectangle(final PlanetModel planetModel, final double bottomLat, final double leftLon, double rightLon) {
-    super(planetModel);
-    // Argument checking
-    if (bottomLat > Math.PI * 0.5 || bottomLat < -Math.PI * 0.5)
-      throw new IllegalArgumentException("Bottom latitude out of range");
-    if (leftLon < -Math.PI || leftLon > Math.PI)
-      throw new IllegalArgumentException("Left longitude out of range");
-    if (rightLon < -Math.PI || rightLon > Math.PI)
-      throw new IllegalArgumentException("Right longitude out of range");
-    double extent = rightLon - leftLon;
-    if (extent < 0.0) {
-      extent += 2.0 * Math.PI;
-    }
-    if (extent > Math.PI)
-      throw new IllegalArgumentException("Width of rectangle too great");
-
-    this.bottomLat = bottomLat;
-    this.leftLon = leftLon;
-    this.rightLon = rightLon;
-
-    final double sinBottomLat = Math.sin(bottomLat);
-    final double cosBottomLat = Math.cos(bottomLat);
-    final double sinLeftLon = Math.sin(leftLon);
-    final double cosLeftLon = Math.cos(leftLon);
-    final double sinRightLon = Math.sin(rightLon);
-    final double cosRightLon = Math.cos(rightLon);
-
-    // Now build the points
-    this.LRHC = new GeoPoint(planetModel, sinBottomLat, sinRightLon, cosBottomLat, cosRightLon, bottomLat, rightLon);
-    this.LLHC = new GeoPoint(planetModel, sinBottomLat, sinLeftLon, cosBottomLat, cosLeftLon, bottomLat, leftLon);
-
-    final double middleLat = (Math.PI * 0.5 + bottomLat) * 0.5;
-    final double sinMiddleLat = Math.sin(middleLat);
-    this.cosMiddleLat = Math.cos(middleLat);
-    // Normalize
-    while (leftLon > rightLon) {
-      rightLon += Math.PI * 2.0;
-    }
-    final double middleLon = (leftLon + rightLon) * 0.5;
-    final double sinMiddleLon = Math.sin(middleLon);
-    final double cosMiddleLon = Math.cos(middleLon);
-
-    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinMiddleLon, cosMiddleLat, cosMiddleLon);
-
-    this.bottomPlane = new SidedPlane(centerPoint, planetModel, sinBottomLat);
-    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
-    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
-
-    this.bottomPlanePoints = new GeoPoint[]{LLHC, LRHC};
-    this.leftPlanePoints = new GeoPoint[]{planetModel.NORTH_POLE, LLHC};
-    this.rightPlanePoints = new GeoPoint[]{planetModel.NORTH_POLE, LRHC};
-
-    this.edgePoints = new GeoPoint[]{planetModel.NORTH_POLE};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    final double newTopLat = Math.PI * 0.5;
-    final double newBottomLat = bottomLat - angle;
-    // Figuring out when we escalate to a special case requires some prefiguring
-    double currentLonSpan = rightLon - leftLon;
-    if (currentLonSpan < 0.0)
-      currentLonSpan += Math.PI * 2.0;
-    double newLeftLon = leftLon - angle;
-    double newRightLon = rightLon + angle;
-    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
-      newLeftLon = -Math.PI;
-      newRightLon = Math.PI;
-    }
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return
-        bottomPlane.isWithin(x, y, z) &&
-            leftPlane.isWithin(x, y, z) &&
-            rightPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public double getRadius() {
-    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
-    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
-    // the distance to the right or left edge from the center.
-    final double centerAngle = (rightLon - (rightLon + leftLon) * 0.5) * cosMiddleLat;
-    final double bottomAngle = centerPoint.arcDistance(LLHC);
-    return Math.max(centerAngle, bottomAngle);
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  /**
-   * Returns the center of a circle into which the area will be inscribed.
-   *
-   * @return the center.
-   */
-  @Override
-  public GeoPoint getCenter() {
-    return centerPoint;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    return
-        p.intersects(planetModel, bottomPlane, notablePoints, bottomPlanePoints, bounds, leftPlane, rightPlane) ||
-            p.intersects(planetModel, leftPlane, notablePoints, leftPlanePoints, bounds, rightPlane, bottomPlane) ||
-            p.intersects(planetModel, rightPlane, notablePoints, rightPlanePoints, bounds, leftPlane, bottomPlane);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds
-      .addHorizontalPlane(planetModel, bottomLat, bottomPlane, leftPlane, rightPlane)
-      .addVerticalPlane(planetModel, leftLon, leftPlane, bottomPlane, rightPlane)
-      .addVerticalPlane(planetModel, rightLon, rightPlane, bottomPlane, leftPlane)
-      .addPoint(LLHC).addPoint(LRHC).addPoint(planetModel.NORTH_POLE);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    //System.err.println(this+" getrelationship with "+path);
-    final int insideRectangle = isShapeInsideBBox(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some inside");
-      return OVERLAPS;
-    }
-
-    final boolean insideShape = path.isWithin(planetModel.NORTH_POLE);
-
-    if (insideRectangle == ALL_INSIDE && insideShape) {
-      //System.err.println(" inside of each other");
-      return OVERLAPS;
-    }
-
-    if (
-        path.intersects(bottomPlane, bottomPlanePoints, leftPlane, rightPlane) ||
-            path.intersects(leftPlane, leftPlanePoints, bottomPlane, rightPlane) ||
-            path.intersects(rightPlane, rightPlanePoints, leftPlane, bottomPlane)) {
-      //System.err.println(" edges intersect");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      //System.err.println(" shape inside rectangle");
-      return WITHIN;
-    }
-
-    if (insideShape) {
-      //System.err.println(" shape contains rectangle");
-      return CONTAINS;
-    }
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    final double bottomDistance = distanceStyle.computeDistance(planetModel, bottomPlane, x,y,z, leftPlane, rightPlane);
-    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, rightPlane, bottomPlane);
-    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, leftPlane, bottomPlane);
-    
-    final double LRHCDistance = distanceStyle.computeDistance(LRHC, x,y,z);
-    final double LLHCDistance = distanceStyle.computeDistance(LLHC, x,y,z);
-    
-    return
-      Math.min(
-        bottomDistance,
-        Math.min(
-          Math.min(leftDistance, rightDistance),
-          Math.min(LRHCDistance, LLHCDistance)));
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoNorthRectangle))
-      return false;
-    GeoNorthRectangle other = (GeoNorthRectangle) o;
-    return super.equals(other) && other.LLHC.equals(LLHC) && other.LRHC.equals(LRHC);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + LLHC.hashCode();
-    result = 31 * result + LRHC.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoNorthRectangle: {planetmodel="+planetModel+", bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
-  }
-}
-  
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoOutsideDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoOutsideDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoOutsideDistance.java
deleted file mode 100644
index c1d784d..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoOutsideDistance.java
+++ /dev/null
@@ -1,55 +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.geo3d;
-
-/**
- * Implemented by Geo3D shapes that can compute the distance from a point to the closest outside edge.
- *
- * @lucene.experimental
- */
-public interface GeoOutsideDistance extends Membership {
-  
-  // The following methods compute distances from the shape to a point
-  // expected to be OUTSIDE the shape.  Typically a value of 0.0
-  // is returned for points that happen to be within the shape.
-  
-  /**
-   * Compute this shape's distance to the GeoPoint.
-   * A return value of 0.0 should be returned for
-   * points inside of the shape.
-   * @param distanceStyle is the distance style.
-   * @param point is the point to compute the distance to.
-   * @return the distance.
-   */
-  public default double computeOutsideDistance(final DistanceStyle distanceStyle, final GeoPoint point) {
-    return computeOutsideDistance(distanceStyle, point.x, point.y, point.z);
-  }
-
-  /**
-   * Compute this shape's distance to the GeoPoint.
-   * A return value of 0.0 should be returned for
-   * points inside of the shape.
-   * @param distanceStyle is the distance style.
-   * @param x is the point's unit x coordinate (using U.S. convention).
-   * @param y is the point's unit y coordinate (using U.S. convention).
-   * @param z is the point's unit z coordinate (using U.S. convention).
-   * @return the distance.
-   */
-  public double computeOutsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z);
-
-}
-


[10/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 0093e26)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XdYZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XdYZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XdYZSolid.java
deleted file mode 100644
index f6a2fa3..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XdYZSolid.java
+++ /dev/null
@@ -1,212 +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.geo3d;
-
-/**
- * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in Y
- *
- * @lucene.internal
- */
-public class XdYZSolid extends BaseXYZSolid {
-
-  /** Min-X plane */
-  protected final SidedPlane minXPlane;
-  /** Max-X plane */
-  protected final SidedPlane maxXPlane;
-  /** Y plane */
-  protected final Plane yPlane;
-  /** Min-Z plane */
-  protected final SidedPlane minZPlane;
-  /** Max-Z plane */
-  protected final SidedPlane maxZPlane;
-  
-  /** These are the edge points of the shape, which are defined to be at least one point on
-   * each surface area boundary.  In the case of a solid, this includes points which represent
-   * the intersection of XYZ bounding planes and the planet, as well as points representing
-   * the intersection of single bounding planes with the planet itself.
-   */
-  protected final GeoPoint[] edgePoints;
-
-  /** Notable points for YPlane */
-  protected final GeoPoint[] notableYPoints;
-
-  /**
-   * Sole constructor
-   *
-   *@param planetModel is the planet model.
-   *@param minX is the minimum X value.
-   *@param maxX is the maximum X value.
-   *@param Y is the Y value.
-   *@param minZ is the minimum Z value.
-   *@param maxZ is the maximum Z value.
-   */
-  public XdYZSolid(final PlanetModel planetModel,
-    final double minX,
-    final double maxX,
-    final double Y,
-    final double minZ,
-    final double maxZ) {
-    super(planetModel);
-    // Argument checking
-    if (maxX - minX < Vector.MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("X values in wrong order or identical");
-    if (maxZ - minZ < Vector.MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("Z values in wrong order or identical");
-
-    final double worldMinY = planetModel.getMinimumYValue();
-    final double worldMaxY = planetModel.getMaximumYValue();
-    
-    // Construct the planes
-    minXPlane = new SidedPlane(maxX,0.0,0.0,xUnitVector,-minX);
-    maxXPlane = new SidedPlane(minX,0.0,0.0,xUnitVector,-maxX);
-    yPlane = new Plane(yUnitVector,-Y);
-    minZPlane = new SidedPlane(0.0,0.0,maxZ,zUnitVector,-minZ);
-    maxZPlane = new SidedPlane(0.0,0.0,minZ,zUnitVector,-maxZ);
-      
-    // We need at least one point on the planet surface for each manifestation of the shape.
-    // There can be up to 2 (on opposite sides of the world).  But we have to go through
-    // 4 combinations of adjacent planes in order to find out if any have 2 intersection solution.
-    // Typically, this requires 4 square root operations. 
-    final GeoPoint[] minXY = minXPlane.findIntersections(planetModel,yPlane,maxXPlane,minZPlane,maxZPlane);
-    final GeoPoint[] maxXY = maxXPlane.findIntersections(planetModel,yPlane,minXPlane,minZPlane,maxZPlane);
-    final GeoPoint[] YminZ = yPlane.findIntersections(planetModel,minZPlane,maxZPlane,minXPlane,maxXPlane);
-    final GeoPoint[] YmaxZ = yPlane.findIntersections(planetModel,maxZPlane,minZPlane,minXPlane,maxXPlane);
-      
-    notableYPoints = glueTogether(minXY, maxXY, YminZ, YmaxZ);
-
-    // Now, compute the edge points.
-    // This is the trickiest part of setting up an XYZSolid.  We've computed intersections already, so
-    // we'll start there.  We know that at most there will be two disconnected shapes on the planet surface.
-    // But there's also a case where exactly one plane slices through the world, and none of the bounding plane
-    // intersections do.  Thus, if we don't find any of the edge intersection cases, we have to look for that last case.
-      
-    // We need to look at single-plane/world intersections.
-    // We detect these by looking at the world model and noting its x, y, and z bounds.
-    // The cases we are looking for are when the four corner points for any given
-    // plane are all outside of the world, AND that plane intersects the world.
-    // There are four corner points all told; we must evaluate these WRT the planet surface.
-    final boolean minXYminZ = planetModel.pointOutside(minX, Y, minZ);
-    final boolean minXYmaxZ = planetModel.pointOutside(minX, Y, maxZ);
-    final boolean maxXYminZ = planetModel.pointOutside(maxX, Y, minZ);
-    final boolean maxXYmaxZ = planetModel.pointOutside(maxX, Y, maxZ);
-
-    final GeoPoint[] yEdges;
-    if (Y - worldMinY >= -Vector.MINIMUM_RESOLUTION && Y - worldMaxY <= Vector.MINIMUM_RESOLUTION &&
-      minX < 0.0 && maxX > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
-      minXYminZ && minXYmaxZ && maxXYminZ && maxXYmaxZ) {
-      // Find any point on the minY plane that intersects the world
-      // First construct a perpendicular plane that will allow us to find a sample point.
-      // This plane is vertical and goes through the points (0,0,0) and (0,1,0)
-      // Then use it to compute a sample point.
-      final GeoPoint intPoint = yPlane.getSampleIntersectionPoint(planetModel, yVerticalPlane);
-      if (intPoint != null) {
-        yEdges = new GeoPoint[]{intPoint};
-      } else {
-        yEdges = EMPTY_POINTS;
-      }
-    } else {
-      yEdges = EMPTY_POINTS;
-    }
-
-    this.edgePoints = glueTogether(minXY, maxXY, YminZ, YmaxZ, yEdges);
-  }
-
-  @Override
-  protected GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-  
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return minXPlane.isWithin(x, y, z) &&
-      maxXPlane.isWithin(x, y, z) &&
-      yPlane.evaluateIsZero(x, y, z) &&
-      minZPlane.isWithin(x, y, z) &&
-      maxZPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    //System.err.println(this+" getrelationship with "+path);
-    final int insideRectangle = isShapeInsideArea(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some inside");
-      return OVERLAPS;
-    }
-
-    // Figure out if the entire XYZArea is contained by the shape.
-    final int insideShape = isAreaInsideShape(path);
-    if (insideShape == SOME_INSIDE) {
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
-      //System.err.println(" inside of each other");
-      return OVERLAPS;
-    }
-
-    if (path.intersects(yPlane, notableYPoints, minXPlane, maxXPlane, minZPlane, maxZPlane)) {
-      //System.err.println(" edges intersect");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      //System.err.println(" shape inside rectangle");
-      return WITHIN;
-    }
-
-    if (insideShape == ALL_INSIDE) {
-      //System.err.println(" shape contains rectangle");
-      return CONTAINS;
-    }
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof XdYZSolid))
-      return false;
-    XdYZSolid other = (XdYZSolid) o;
-    if (!super.equals(other)) {
-      return false;
-    }
-    return other.minXPlane.equals(minXPlane) &&
-      other.maxXPlane.equals(maxXPlane) &&
-      other.yPlane.equals(yPlane) &&
-      other.minZPlane.equals(minZPlane) &&
-      other.maxZPlane.equals(maxZPlane);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result  + minXPlane.hashCode();
-    result = 31 * result  + maxXPlane.hashCode();
-    result = 31 * result  + yPlane.hashCode();
-    result = 31 * result  + minZPlane.hashCode();
-    result = 31 * result  + maxZPlane.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "XdYZSolid: {planetmodel="+planetModel+", minXplane="+minXPlane+", maxXplane="+maxXPlane+", yplane="+yPlane+", minZplane="+minZPlane+", maxZplane="+maxZPlane+"}";
-  }
-  
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XdYdZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XdYdZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XdYdZSolid.java
deleted file mode 100644
index 562e5a6..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XdYdZSolid.java
+++ /dev/null
@@ -1,138 +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.geo3d;
-
-/**
- * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in Y and Z.
- * This figure, in fact, represents either zero, one, or two points, so the
- * actual data stored is minimal.
- *
- * @lucene.internal
- */
-public class XdYdZSolid extends BaseXYZSolid {
-
-  /** The points in this figure on the planet surface; also doubles for edge points */
-  protected final GeoPoint[] surfacePoints;
-  
-  /**
-   * Sole constructor
-   *
-   *@param planetModel is the planet model.
-   *@param minX is the minimum X value.
-   *@param maxX is the maximum X value.
-   *@param Y is the Y value.
-   *@param Z is the Z value.
-   */
-  public XdYdZSolid(final PlanetModel planetModel,
-    final double minX,
-    final double maxX,
-    final double Y,
-    final double Z) {
-    super(planetModel);
-    // Argument checking
-    if (maxX - minX < Vector.MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("X values in wrong order or identical");
-
-    // Build the planes and intersect them.
-    final Plane yPlane = new Plane(yUnitVector,-Y);
-    final Plane zPlane = new Plane(zUnitVector,-Z);
-    final SidedPlane minXPlane = new SidedPlane(maxX,0.0,0.0,xUnitVector,-minX);
-    final SidedPlane maxXPlane = new SidedPlane(minX,0.0,0.0,xUnitVector,-maxX);
-    surfacePoints = yPlane.findIntersections(planetModel,zPlane,minXPlane,maxXPlane);
-  }
-
-  @Override
-  protected GeoPoint[] getEdgePoints() {
-    return surfacePoints;
-  }
-  
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    for (final GeoPoint p : surfacePoints) {
-      if (p.isIdentical(x,y,z))
-        return true;
-    }
-    return false;
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    //System.err.println(this+" getrelationship with "+path);
-    final int insideRectangle = isShapeInsideArea(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some inside");
-      return OVERLAPS;
-    }
-
-    // Figure out if the entire XYZArea is contained by the shape.
-    final int insideShape = isAreaInsideShape(path);
-    if (insideShape == SOME_INSIDE) {
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
-      //System.err.println(" inside of each other");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      return WITHIN;
-    }
-    
-    if (insideShape == ALL_INSIDE) {
-      //System.err.println(" shape contains rectangle");
-      return CONTAINS;
-    }
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof XdYdZSolid))
-      return false;
-    XdYdZSolid other = (XdYdZSolid) o;
-    if (!super.equals(other) || surfacePoints.length != other.surfacePoints.length ) {
-      return false;
-    }
-    for (int i = 0; i < surfacePoints.length; i++) {
-      if (!surfacePoints[i].equals(other.surfacePoints[i]))
-        return false;
-    }
-    return true;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    for (final GeoPoint p : surfacePoints) {
-      result = 31 * result  + p.hashCode();
-    }
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    final StringBuilder sb = new StringBuilder();
-    for (final GeoPoint p : surfacePoints) {
-      sb.append(" ").append(p).append(" ");
-    }
-    return "XdYdZSolid: {planetmodel="+planetModel+", "+sb.toString()+"}";
-  }
-  
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXYZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXYZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXYZSolid.java
deleted file mode 100644
index 5a2a006..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXYZSolid.java
+++ /dev/null
@@ -1,216 +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.geo3d;
-
-/**
- * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in X.
- *
- * @lucene.internal
- */
-public class dXYZSolid extends BaseXYZSolid {
-
-  /** X plane */
-  protected final Plane xPlane;
-  /** Min-Y plane */
-  protected final SidedPlane minYPlane;
-  /** Max-Y plane */
-  protected final SidedPlane maxYPlane;
-  /** Min-Z plane */
-  protected final SidedPlane minZPlane;
-  /** Max-Z plane */
-  protected final SidedPlane maxZPlane;
-  
-  /** These are the edge points of the shape, which are defined to be at least one point on
-   * each surface area boundary.  In the case of a solid, this includes points which represent
-   * the intersection of XYZ bounding planes and the planet, as well as points representing
-   * the intersection of single bounding planes with the planet itself.
-   */
-  protected final GeoPoint[] edgePoints;
-
-  /** Notable points for XPlane */
-  protected final GeoPoint[] notableXPoints;
-
-  /**
-   * Sole constructor
-   *
-   *@param planetModel is the planet model.
-   *@param X is the X value.
-   *@param minY is the minimum Y value.
-   *@param maxY is the maximum Y value.
-   *@param minZ is the minimum Z value.
-   *@param maxZ is the maximum Z value.
-   */
-  public dXYZSolid(final PlanetModel planetModel,
-    final double X,
-    final double minY,
-    final double maxY,
-    final double minZ,
-    final double maxZ) {
-    super(planetModel);
-    // Argument checking
-    if (maxY - minY < Vector.MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("Y values in wrong order or identical");
-    if (maxZ - minZ < Vector.MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("Z values in wrong order or identical");
-
-    final double worldMinX = planetModel.getMinimumXValue();
-    final double worldMaxX = planetModel.getMaximumXValue();
-    
-    // Construct the planes
-    xPlane = new Plane(xUnitVector,-X);
-    minYPlane = new SidedPlane(0.0,maxY,0.0,yUnitVector,-minY);
-    maxYPlane = new SidedPlane(0.0,minY,0.0,yUnitVector,-maxY);
-    minZPlane = new SidedPlane(0.0,0.0,maxZ,zUnitVector,-minZ);
-    maxZPlane = new SidedPlane(0.0,0.0,minZ,zUnitVector,-maxZ);
-      
-    // We need at least one point on the planet surface for each manifestation of the shape.
-    // There can be up to 2 (on opposite sides of the world).  But we have to go through
-    // 4 combinations of adjacent planes in order to find out if any have 2 intersection solution.
-    // Typically, this requires 4 square root operations. 
-    final GeoPoint[] XminY = xPlane.findIntersections(planetModel,minYPlane,maxYPlane,minZPlane,maxZPlane);
-    final GeoPoint[] XmaxY = xPlane.findIntersections(planetModel,maxYPlane,minYPlane,minZPlane,maxZPlane);
-    final GeoPoint[] XminZ = xPlane.findIntersections(planetModel,minZPlane,maxZPlane,minYPlane,maxYPlane);
-    final GeoPoint[] XmaxZ = xPlane.findIntersections(planetModel,maxZPlane,minZPlane,minYPlane,maxYPlane);
-
-    notableXPoints = glueTogether(XminY, XmaxY, XminZ, XmaxZ);
-
-    // Now, compute the edge points.
-    // This is the trickiest part of setting up an XYZSolid.  We've computed intersections already, so
-    // we'll start there.  We know that at most there will be two disconnected shapes on the planet surface.
-    // But there's also a case where exactly one plane slices through the world, and none of the bounding plane
-    // intersections do.  Thus, if we don't find any of the edge intersection cases, we have to look for that last case.
-      
-    // We need to look at single-plane/world intersections.
-    // We detect these by looking at the world model and noting its x, y, and z bounds.
-    // For the single-dimension degenerate case, there's really only one plane that can possibly intersect the world.
-    // The cases we are looking for are when the four corner points for any given
-    // plane are all outside of the world, AND that plane intersects the world.
-    // There are four corner points all told; we must evaluate these WRT the planet surface.
-    final boolean XminYminZ = planetModel.pointOutside(X, minY, minZ);
-    final boolean XminYmaxZ = planetModel.pointOutside(X, minY, maxZ);
-    final boolean XmaxYminZ = planetModel.pointOutside(X, maxY, minZ);
-    final boolean XmaxYmaxZ = planetModel.pointOutside(X, maxY, maxZ);
-
-    final GeoPoint[] xEdges;
-    if (X - worldMinX >= -Vector.MINIMUM_RESOLUTION && X - worldMaxX <= Vector.MINIMUM_RESOLUTION &&
-      minY < 0.0 && maxY > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
-      XminYminZ && XminYmaxZ && XmaxYminZ && XmaxYmaxZ) {
-      // Find any point on the X plane that intersects the world
-      // First construct a perpendicular plane that will allow us to find a sample point.
-      // This plane is vertical and goes through the points (0,0,0) and (1,0,0)
-      // Then use it to compute a sample point.
-      final GeoPoint intPoint = xPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
-      if (intPoint != null) {
-        xEdges = new GeoPoint[]{intPoint};
-      } else {
-        xEdges = EMPTY_POINTS;
-      }
-    } else {
-      xEdges = EMPTY_POINTS;
-    }
-
-    this.edgePoints = glueTogether(XminY,XmaxY,XminZ,XmaxZ,xEdges);
-  }
-
-  @Override
-  protected GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-  
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return xPlane.evaluateIsZero(x, y, z) &&
-      minYPlane.isWithin(x, y, z) &&
-      maxYPlane.isWithin(x, y, z) &&
-      minZPlane.isWithin(x, y, z) &&
-      maxZPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    //System.err.println(this+" getrelationship with "+path);
-    final int insideRectangle = isShapeInsideArea(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some shape points inside area");
-      return OVERLAPS;
-    }
-
-    // Figure out if the entire XYZArea is contained by the shape.
-    final int insideShape = isAreaInsideShape(path);
-    if (insideShape == SOME_INSIDE) {
-      //System.err.println(" some area points inside shape");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
-      //System.err.println(" inside of each other");
-      return OVERLAPS;
-    }
-
-    // The entire locus of points in this shape is on a single plane, so we only need ot look for an intersection with that plane.
-    //System.err.println("xPlane = "+xPlane);
-    if (path.intersects(xPlane, notableXPoints, minYPlane, maxYPlane, minZPlane, maxZPlane)) {
-      //System.err.println(" edges intersect");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      //System.err.println(" shape points inside area");
-      return WITHIN;
-    }
-
-    if (insideShape == ALL_INSIDE) {
-      //System.err.println(" shape contains all area");
-      return CONTAINS;
-    }
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof dXYZSolid))
-      return false;
-    dXYZSolid other = (dXYZSolid) o;
-    if (!super.equals(other)) {
-      return false;
-    }
-    return other.xPlane.equals(xPlane) &&
-      other.minYPlane.equals(minYPlane) &&
-      other.maxYPlane.equals(maxYPlane) &&
-      other.minZPlane.equals(minZPlane) &&
-      other.maxZPlane.equals(maxZPlane);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result  + xPlane.hashCode();
-    result = 31 * result  + minYPlane.hashCode();
-    result = 31 * result  + maxYPlane.hashCode();
-    result = 31 * result  + minZPlane.hashCode();
-    result = 31 * result  + maxZPlane.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "dXYZSolid: {planetmodel="+planetModel+", xplane="+xPlane+", minYplane="+minYPlane+", maxYplane="+maxYPlane+", minZplane="+minZPlane+", maxZplane="+maxZPlane+"}";
-  }
-  
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXYdZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXYdZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXYdZSolid.java
deleted file mode 100644
index 96b3004..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXYdZSolid.java
+++ /dev/null
@@ -1,138 +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.geo3d;
-
-/**
- * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in X and Z.
- * This figure, in fact, represents either zero, one, or two points, so the
- * actual data stored is minimal.
- *
- * @lucene.internal
- */
-public class dXYdZSolid extends BaseXYZSolid {
-
-  /** The points in this figure on the planet surface; also doubles for edge points */
-  protected final GeoPoint[] surfacePoints;
-  
-  /**
-   * Sole constructor
-   *
-   *@param planetModel is the planet model.
-   *@param X is the X value.
-   *@param minY is the minimum Y value.
-   *@param maxY is the maximum Y value.
-   *@param Z is the Z value.
-   */
-  public dXYdZSolid(final PlanetModel planetModel,
-    final double X,
-    final double minY,
-    final double maxY,
-    final double Z) {
-    super(planetModel);
-    // Argument checking
-    if (maxY - minY < Vector.MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("Y values in wrong order or identical");
-
-    // Build the planes and intersect them.
-    final Plane xPlane = new Plane(xUnitVector,-X);
-    final Plane zPlane = new Plane(zUnitVector,-Z);
-    final SidedPlane minYPlane = new SidedPlane(0.0,maxY,0.0,yUnitVector,-minY);
-    final SidedPlane maxYPlane = new SidedPlane(0.0,minY,0.0,yUnitVector,-maxY);
-    surfacePoints = xPlane.findIntersections(planetModel,zPlane,minYPlane,maxYPlane);
-  }
-
-  @Override
-  protected GeoPoint[] getEdgePoints() {
-    return surfacePoints;
-  }
-  
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    for (final GeoPoint p : surfacePoints) {
-      if (p.isIdentical(x,y,z))
-        return true;
-    }
-    return false;
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    //System.err.println(this+" getrelationship with "+path);
-    final int insideRectangle = isShapeInsideArea(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some inside");
-      return OVERLAPS;
-    }
-
-    // Figure out if the entire XYZArea is contained by the shape.
-    final int insideShape = isAreaInsideShape(path);
-    if (insideShape == SOME_INSIDE) {
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
-      //System.err.println(" inside of each other");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      return WITHIN;
-    }
-    
-    if (insideShape == ALL_INSIDE) {
-      //System.err.println(" shape contains rectangle");
-      return CONTAINS;
-    }
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof dXYdZSolid))
-      return false;
-    dXYdZSolid other = (dXYdZSolid) o;
-    if (!super.equals(other) || surfacePoints.length != other.surfacePoints.length ) {
-      return false;
-    }
-    for (int i = 0; i < surfacePoints.length; i++) {
-      if (!surfacePoints[i].equals(other.surfacePoints[i]))
-        return false;
-    }
-    return true;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    for (final GeoPoint p : surfacePoints) {
-      result = 31 * result  + p.hashCode();
-    }
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    final StringBuilder sb = new StringBuilder();
-    for (final GeoPoint p : surfacePoints) {
-      sb.append(" ").append(p).append(" ");
-    }
-    return "dXYdZSolid: {planetmodel="+planetModel+", "+sb.toString()+"}";
-  }
-  
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXdYZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXdYZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXdYZSolid.java
deleted file mode 100644
index b58cd92..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXdYZSolid.java
+++ /dev/null
@@ -1,138 +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.geo3d;
-
-/**
- * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in X and Y.
- * This figure, in fact, represents either zero, one, or two points, so the
- * actual data stored is minimal.
- *
- * @lucene.internal
- */
-public class dXdYZSolid extends BaseXYZSolid {
-
-  /** The points in this figure on the planet surface; also doubles for edge points */
-  protected final GeoPoint[] surfacePoints;
-  
-  /**
-   * Sole constructor
-   *
-   *@param planetModel is the planet model.
-   *@param X is the X value.
-   *@param Y is the Y value.
-   *@param minZ is the minimum Z value.
-   *@param maxZ is the maximum Z value.
-   */
-  public dXdYZSolid(final PlanetModel planetModel,
-    final double X,
-    final double Y,
-    final double minZ,
-    final double maxZ) {
-    super(planetModel);
-    // Argument checking
-    if (maxZ - minZ < Vector.MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("Z values in wrong order or identical");
-
-    // Build the planes and intersect them.
-    final Plane xPlane = new Plane(xUnitVector,-X);
-    final Plane yPlane = new Plane(yUnitVector,-Y);
-    final SidedPlane minZPlane = new SidedPlane(0.0,0.0,maxZ,zUnitVector,-minZ);
-    final SidedPlane maxZPlane = new SidedPlane(0.0,0.0,minZ,zUnitVector,-maxZ);
-    surfacePoints = xPlane.findIntersections(planetModel,yPlane,minZPlane,maxZPlane);
-  }
-
-  @Override
-  protected GeoPoint[] getEdgePoints() {
-    return surfacePoints;
-  }
-  
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    for (final GeoPoint p : surfacePoints) {
-      if (p.isIdentical(x,y,z))
-        return true;
-    }
-    return false;
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    //System.err.println(this+" getrelationship with "+path);
-    final int insideRectangle = isShapeInsideArea(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some inside");
-      return OVERLAPS;
-    }
-
-    // Figure out if the entire XYZArea is contained by the shape.
-    final int insideShape = isAreaInsideShape(path);
-    if (insideShape == SOME_INSIDE) {
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
-      //System.err.println(" inside of each other");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      return WITHIN;
-    }
-    
-    if (insideShape == ALL_INSIDE) {
-      //System.err.println(" shape contains rectangle");
-      return CONTAINS;
-    }
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof dXdYZSolid))
-      return false;
-    dXdYZSolid other = (dXdYZSolid) o;
-    if (!super.equals(other) || surfacePoints.length != other.surfacePoints.length ) {
-      return false;
-    }
-    for (int i = 0; i < surfacePoints.length; i++) {
-      if (!surfacePoints[i].equals(other.surfacePoints[i]))
-        return false;
-    }
-    return true;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    for (final GeoPoint p : surfacePoints) {
-      result = 31 * result  + p.hashCode();
-    }
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    final StringBuilder sb = new StringBuilder();
-    for (final GeoPoint p : surfacePoints) {
-      sb.append(" ").append(p).append(" ");
-    }
-    return "dXdYZSolid: {planetmodel="+planetModel+", "+sb.toString()+"}";
-  }
-  
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXdYdZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXdYdZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXdYdZSolid.java
deleted file mode 100644
index b26cf63..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXdYdZSolid.java
+++ /dev/null
@@ -1,146 +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.geo3d;
-
-/**
- * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in all dimensions
- *
- * @lucene.internal
- */
-public class dXdYdZSolid extends BaseXYZSolid {
-
-  /** On surface? */
-  protected final boolean isOnSurface;
-  /** The point */
-  protected final GeoPoint thePoint;
-  
-  /** These are the edge points of the shape, which are defined to be at least one point on
-   * each surface area boundary.  In the case of a solid, this includes points which represent
-   * the intersection of XYZ bounding planes and the planet, as well as points representing
-   * the intersection of single bounding planes with the planet itself.
-   */
-  protected final GeoPoint[] edgePoints;
-
-  /** Empty array of {@link GeoPoint}. */
-  protected static final GeoPoint[] nullPoints = new GeoPoint[0];
-  
-  /**
-   * Sole constructor
-   *
-   *@param planetModel is the planet model.
-   *@param X is the X value.
-   *@param Y is the Y value.
-   *@param Z is the Z value.
-   */
-  public dXdYdZSolid(final PlanetModel planetModel,
-    final double X,
-    final double Y,
-    final double Z) {
-    super(planetModel);
-    isOnSurface = planetModel.pointOnSurface(X,Y,Z);
-    if (isOnSurface) {
-      thePoint = new GeoPoint(X,Y,Z);
-      edgePoints = new GeoPoint[]{thePoint};
-    } else {
-      thePoint = null;
-      edgePoints = nullPoints;
-    }
-  }
-
-  @Override
-  protected GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-  
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    if (!isOnSurface) {
-      return false;
-    }
-    return thePoint.isIdentical(x,y,z);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    if (!isOnSurface) {
-      return DISJOINT;
-    }
-    
-    //System.err.println(this+" getrelationship with "+path);
-    final int insideRectangle = isShapeInsideArea(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some shape points inside area");
-      return OVERLAPS;
-    }
-
-    // Figure out if the entire XYZArea is contained by the shape.
-    final int insideShape = isAreaInsideShape(path);
-    if (insideShape == SOME_INSIDE) {
-      //System.err.println(" some area points inside shape");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
-      //System.err.println(" inside of each other");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      //System.err.println(" shape inside area entirely");
-      return WITHIN;
-    }
-
-    if (insideShape == ALL_INSIDE) {
-      //System.err.println(" shape contains area entirely");
-      return CONTAINS;
-    }
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof dXdYdZSolid))
-      return false;
-    dXdYdZSolid other = (dXdYdZSolid) o;
-    if (!super.equals(other) ||
-      other.isOnSurface != isOnSurface) {
-      return false;
-    }
-    if (isOnSurface) {
-      return other.thePoint.equals(thePoint);
-    }
-    return true;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + (isOnSurface?1:0);
-    if (isOnSurface) {
-      result = 31 * result  + thePoint.hashCode();
-    }
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "dXdYdZSolid: {planetmodel="+planetModel+", isOnSurface="+isOnSurface+", thePoint="+thePoint+"}";
-  }
-  
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/package-info.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/package-info.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/package-info.java
deleted file mode 100644
index 2b6af74..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/package-info.java
+++ /dev/null
@@ -1,21 +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.
- */
-
-/**
- * Shapes implemented using 3D planar geometry.
- */
-package org.apache.lucene.geo3d;

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPoint.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPoint.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPoint.java
new file mode 100644
index 0000000..cd2c79a
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPoint.java
@@ -0,0 +1,114 @@
+/*
+ * 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.spatial3d;
+
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.FieldType;
+import org.apache.lucene.spatial3d.geom.GeoPoint;
+import org.apache.lucene.spatial3d.geom.GeoShape;
+import org.apache.lucene.spatial3d.geom.PlanetModel;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.util.BytesRef;
+import org.apache.lucene.util.NumericUtils;
+
+/**
+ * Add this to a document to index lat/lon or x/y/z point, indexed as a 3D point.
+ * Multiple values are allowed: just add multiple Geo3DPoint to the document with the
+ * same field name.
+ * <p>
+ * This field defines static factory methods for creating a shape query:
+ * <ul>
+ *   <li>{@link #newShapeQuery newShapeQuery()} for matching all points inside a specified shape
+ * </ul>
+ *
+ *  @lucene.experimental */
+public final class Geo3DPoint extends Field {
+
+  /** Indexing {@link FieldType}. */
+  public static final FieldType TYPE = new FieldType();
+  static {
+    TYPE.setDimensions(3, Integer.BYTES);
+    TYPE.freeze();
+  }
+
+  /** 
+   * Creates a new Geo3DPoint field with the specified lat, lon (in radians).
+   *
+   * @throws IllegalArgumentException if the field name is null or lat or lon are out of bounds
+   */
+  public Geo3DPoint(String name, double lat, double lon) {
+    super(name, TYPE);
+    // Translate lat/lon to x,y,z:
+    final GeoPoint point = new GeoPoint(PlanetModel.WGS84, lat, lon);
+    fillFieldsData(point.x, point.y, point.z);
+  }
+
+  /** 
+   * Creates a new Geo3DPoint field with the specified x,y,z.
+   *
+   * @throws IllegalArgumentException if the field name is null or lat or lon are out of bounds
+   */
+  public Geo3DPoint(String name, double x, double y, double z) {
+    super(name, TYPE);
+    fillFieldsData(x, y, z);
+  }
+
+  private void fillFieldsData(double x, double y, double z) {
+    byte[] bytes = new byte[12];
+    encodeDimension(x, bytes, 0);
+    encodeDimension(y, bytes, Integer.BYTES);
+    encodeDimension(z, bytes, 2*Integer.BYTES);
+    fieldsData = new BytesRef(bytes);
+  }
+
+  // public helper methods (e.g. for queries)
+  
+  /** Encode single dimension */
+  public static void encodeDimension(double value, byte bytes[], int offset) {
+    NumericUtils.intToSortableBytes(Geo3DUtil.encodeValue(PlanetModel.WGS84.getMaximumMagnitude(), value), bytes, offset);
+  }
+  
+  /** Decode single dimension */
+  public static double decodeDimension(byte value[], int offset) {
+    return Geo3DUtil.decodeValueCenter(PlanetModel.WGS84.getMaximumMagnitude(), NumericUtils.sortableBytesToInt(value, offset));
+  }
+
+  /** Returns a query matching all points inside the provided shape.
+   * 
+   * @param field field name. must not be {@code null}.
+   * @param shape Which {@link GeoShape} to match
+   */
+  public static Query newShapeQuery(String field, GeoShape shape) {
+    return new PointInGeo3DShapeQuery(field, shape);
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder result = new StringBuilder();
+    result.append(getClass().getSimpleName());
+    result.append(" <");
+    result.append(name);
+    result.append(':');
+
+    BytesRef bytes = (BytesRef) fieldsData;
+    result.append(" x=" + decodeDimension(bytes.bytes, bytes.offset));
+    result.append(" y=" + decodeDimension(bytes.bytes, bytes.offset + Integer.BYTES));
+    result.append(" z=" + decodeDimension(bytes.bytes, bytes.offset + 2*Integer.BYTES));
+    result.append('>');
+    return result.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DUtil.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DUtil.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DUtil.java
new file mode 100644
index 0000000..0a0bf30
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DUtil.java
@@ -0,0 +1,59 @@
+/*
+ * 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.spatial3d;
+
+class Geo3DUtil {
+
+  /** Clips the incoming value to the allowed min/max range before encoding, instead of throwing an exception. */
+  public static int encodeValueLenient(double planetMax, double x) {
+    if (x > planetMax) {
+      x = planetMax;
+    } else if (x < -planetMax) {
+      x = -planetMax;
+    }
+    return encodeValue(planetMax, x);
+  }
+
+  public static int encodeValue(double planetMax, double x) {
+    if (x > planetMax) {
+      throw new IllegalArgumentException("value=" + x + " is out-of-bounds (greater than planetMax=" + planetMax + ")");
+    }
+    if (x < -planetMax) {
+      throw new IllegalArgumentException("value=" + x + " is out-of-bounds (less than than -planetMax=" + -planetMax + ")");
+    }
+    long y = Math.round (x * (Integer.MAX_VALUE / planetMax));
+    assert y >= Integer.MIN_VALUE;
+    assert y <= Integer.MAX_VALUE;
+
+    return (int) y;
+  }
+
+  /** Center decode */
+  public static double decodeValueCenter(double planetMax, int x) {
+    return x * (planetMax / Integer.MAX_VALUE);
+  }
+
+  /** More negative decode, at bottom of cell */
+  public static double decodeValueMin(double planetMax, int x) {
+    return (((double)x) - 0.5) * (planetMax / Integer.MAX_VALUE);
+  }
+  
+  /** More positive decode, at top of cell  */
+  public static double decodeValueMax(double planetMax, int x) {
+    return (((double)x) + 0.5) * (planetMax / Integer.MAX_VALUE);
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/PointInGeo3DShapeQuery.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/PointInGeo3DShapeQuery.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/PointInGeo3DShapeQuery.java
new file mode 100644
index 0000000..9df8752
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/PointInGeo3DShapeQuery.java
@@ -0,0 +1,215 @@
+/*
+ * 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.spatial3d;
+
+import java.io.IOException;
+
+import org.apache.lucene.spatial3d.geom.BasePlanetObject;
+import org.apache.lucene.spatial3d.geom.GeoArea;
+import org.apache.lucene.spatial3d.geom.GeoAreaFactory;
+import org.apache.lucene.spatial3d.geom.GeoShape;
+import org.apache.lucene.spatial3d.geom.PlanetModel;
+import org.apache.lucene.index.PointValues.IntersectVisitor;
+import org.apache.lucene.index.PointValues;
+import org.apache.lucene.index.PointValues.Relation;
+import org.apache.lucene.index.LeafReader;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.search.ConstantScoreScorer;
+import org.apache.lucene.search.ConstantScoreWeight;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.Scorer;
+import org.apache.lucene.search.Weight;
+import org.apache.lucene.util.DocIdSetBuilder;
+import org.apache.lucene.util.NumericUtils;
+
+/** Finds all previously indexed points that fall within the specified polygon.
+ *
+ * <p>The field must be indexed using {@link Geo3DPoint}.
+ *
+ * @lucene.experimental */
+
+class PointInGeo3DShapeQuery extends Query {
+  final String field;
+  final GeoShape shape;
+
+  /** The lats/lons must be clockwise or counter-clockwise. */
+  public PointInGeo3DShapeQuery(String field, GeoShape shape) {
+    this.field = field;
+    this.shape = shape;
+
+    if (shape instanceof BasePlanetObject) {
+      BasePlanetObject planetObject = (BasePlanetObject) shape;
+      if (planetObject.getPlanetModel().equals(PlanetModel.WGS84) == false) {
+        throw new IllegalArgumentException("this qurey requires PlanetModel.WGS84, but got: " + planetObject.getPlanetModel());
+      }
+    }
+  }
+
+  @Override
+  public Weight createWeight(IndexSearcher searcher, boolean needsScores) throws IOException {
+
+    // I don't use RandomAccessWeight here: it's no good to approximate with "match all docs"; this is an inverted structure and should be
+    // used in the first pass:
+
+    return new ConstantScoreWeight(this) {
+
+      @Override
+      public Scorer scorer(LeafReaderContext context) throws IOException {
+        LeafReader reader = context.reader();
+        PointValues values = reader.getPointValues();
+        if (values == null) {
+          return null;
+        }
+
+        /*
+        XYZBounds bounds = new XYZBounds();
+        shape.getBounds(bounds);
+
+        final double planetMax = planetModel.getMaximumMagnitude();
+        if (planetMax != treeDV.planetMax) {
+          throw new IllegalStateException(planetModel + " is not the same one used during indexing: planetMax=" + planetMax + " vs indexing planetMax=" + treeDV.planetMax);
+        }
+        */
+
+        /*
+        GeoArea xyzSolid = GeoAreaFactory.makeGeoArea(planetModel,
+                                                      bounds.getMinimumX(),
+                                                      bounds.getMaximumX(),
+                                                      bounds.getMinimumY(),
+                                                      bounds.getMaximumY(),
+                                                      bounds.getMinimumZ(),
+                                                      bounds.getMaximumZ());
+
+        assert xyzSolid.getRelationship(shape) == GeoArea.WITHIN || xyzSolid.getRelationship(shape) == GeoArea.OVERLAPS: "expected WITHIN (1) or OVERLAPS (2) but got " + xyzSolid.getRelationship(shape) + "; shape="+shape+"; XYZSolid="+xyzSolid;
+        */
+
+        double planetMax = PlanetModel.WGS84.getMaximumMagnitude();
+
+        DocIdSetBuilder result = new DocIdSetBuilder(reader.maxDoc());
+
+        values.intersect(field,
+                         new IntersectVisitor() {
+
+                           @Override
+                           public void visit(int docID) {
+                             result.add(docID);
+                           }
+
+                           @Override
+                           public void visit(int docID, byte[] packedValue) {
+                             assert packedValue.length == 12;
+                             double x = Geo3DPoint.decodeDimension(packedValue, 0);
+                             double y = Geo3DPoint.decodeDimension(packedValue, Integer.BYTES);
+                             double z = Geo3DPoint.decodeDimension(packedValue, 2 * Integer.BYTES);
+                             if (shape.isWithin(x, y, z)) {
+                               result.add(docID);
+                             }
+                           }
+
+                           @Override
+                           public Relation compare(byte[] minPackedValue, byte[] maxPackedValue) {
+                             // Because the dimensional format operates in quantized (64 bit -> 32 bit) space, and the cell bounds
+                             // here are inclusive, we need to extend the bounds to the largest un-quantized values that
+                             // could quantize into these bounds.  The encoding (Geo3DUtil.encodeValue) does
+                             // a Math.round from double to long, so e.g. 1.4 -> 1, and -1.4 -> -1:
+                             double xMin = Geo3DUtil.decodeValueMin(planetMax, NumericUtils.sortableBytesToInt(minPackedValue, 0));
+                             double xMax = Geo3DUtil.decodeValueMax(planetMax, NumericUtils.sortableBytesToInt(maxPackedValue, 0));
+                             double yMin = Geo3DUtil.decodeValueMin(planetMax, NumericUtils.sortableBytesToInt(minPackedValue, 1 * Integer.BYTES));
+                             double yMax = Geo3DUtil.decodeValueMax(planetMax, NumericUtils.sortableBytesToInt(maxPackedValue, 1 * Integer.BYTES));
+                             double zMin = Geo3DUtil.decodeValueMin(planetMax, NumericUtils.sortableBytesToInt(minPackedValue, 2 * Integer.BYTES));
+                             double zMax = Geo3DUtil.decodeValueMax(planetMax, NumericUtils.sortableBytesToInt(maxPackedValue, 2 * Integer.BYTES));
+
+                             //System.out.println("  compare: x=" + cellXMin + "-" + cellXMax + " y=" + cellYMin + "-" + cellYMax + " z=" + cellZMin + "-" + cellZMax);
+                             assert xMin <= xMax;
+                             assert yMin <= yMax;
+                             assert zMin <= zMax;
+
+                             GeoArea xyzSolid = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84, xMin, xMax, yMin, yMax, zMin, zMax);
+
+                             switch(xyzSolid.getRelationship(shape)) {
+                             case GeoArea.CONTAINS:
+                               // Shape fully contains the cell
+                               //System.out.println("    inside");
+                               return Relation.CELL_INSIDE_QUERY;
+                             case GeoArea.OVERLAPS:
+                               // They do overlap but neither contains the other:
+                               //System.out.println("    crosses1");
+                               return Relation.CELL_CROSSES_QUERY;
+                             case GeoArea.WITHIN:
+                               // Cell fully contains the shape:
+                               //System.out.println("    crosses2");
+                               // return Relation.SHAPE_INSIDE_CELL;
+                               return Relation.CELL_CROSSES_QUERY;
+                             case GeoArea.DISJOINT:
+                               // They do not overlap at all
+                               //System.out.println("    outside");
+                               return Relation.CELL_OUTSIDE_QUERY;
+                             default:
+                               assert false;
+                               return Relation.CELL_CROSSES_QUERY;
+                             }
+                           }
+                         });
+
+        return new ConstantScoreScorer(this, score(), result.build().iterator());
+      }
+    };
+  }
+
+  public String getField() {
+    return field;
+  }
+
+  public GeoShape getShape() {
+    return shape;
+  }
+
+  @Override
+  @SuppressWarnings({"unchecked","rawtypes"})
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+    if (!super.equals(o)) return false;
+
+    PointInGeo3DShapeQuery that = (PointInGeo3DShapeQuery) o;
+
+    return shape.equals(that.shape);
+  }
+
+  @Override
+  public final int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + shape.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString(String field) {
+    final StringBuilder sb = new StringBuilder();
+    sb.append(getClass().getSimpleName());
+    sb.append(':');
+    if (this.field.equals(field) == false) {
+      sb.append(" field=");
+      sb.append(this.field);
+      sb.append(':');
+    }
+    sb.append(" Shape: ");
+    sb.append(shape);
+    return sb.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/ArcDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/ArcDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/ArcDistance.java
new file mode 100644
index 0000000..bb60be0
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/ArcDistance.java
@@ -0,0 +1,56 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Arc distance computation style.
+ *
+ * @lucene.experimental
+ */
+public class ArcDistance implements DistanceStyle {
+  
+  /** An instance of the ArcDistance DistanceStyle. */
+  public final static ArcDistance INSTANCE = new ArcDistance();
+  
+  /** Constructor.
+   */
+  public ArcDistance() {
+  }
+  
+  @Override
+  public double computeDistance(final GeoPoint point1, final GeoPoint point2) {
+    return point1.arcDistance(point2);
+  }
+  
+  @Override
+  public double computeDistance(final GeoPoint point1, final double x2, final double y2, final double z2) {
+    return point1.arcDistance(x2,y2,z2);
+  }
+
+  @Override
+  public double computeDistance(final PlanetModel planetModel, final Plane plane, final GeoPoint point, final Membership... bounds) {
+    return plane.arcDistance(planetModel, point, bounds);
+  }
+  
+  @Override
+  public double computeDistance(final PlanetModel planetModel, final Plane plane, final double x, final double y, final double z, final Membership... bounds) {
+    return plane.arcDistance(planetModel, x,y,z, bounds);
+  }
+
+}
+
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/BasePlanetObject.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/BasePlanetObject.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/BasePlanetObject.java
new file mode 100644
index 0000000..5cd5acc
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/BasePlanetObject.java
@@ -0,0 +1,57 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * All Geo3D shapes can derive from this base class, which furnishes
+ * some common code
+ *
+ * @lucene.internal
+ */
+public abstract class BasePlanetObject {
+
+  /** This is the planet model embedded in all objects derived from this
+   * class. */
+  protected final PlanetModel planetModel;
+  
+  /** Constructor creating class instance given a planet model.
+   * @param planetModel is the planet model.
+   */
+  public BasePlanetObject(final PlanetModel planetModel) {
+    this.planetModel = planetModel;
+  }
+
+  /** Returns the {@link PlanetModel} provided when this shape was created. */
+  public PlanetModel getPlanetModel() {
+    return planetModel;
+  }
+  
+  @Override
+  public int hashCode() {
+    return planetModel.hashCode();
+  }
+  
+  @Override
+  public boolean equals(final Object o) {
+    if (!(o instanceof BasePlanetObject))
+      return false;
+    return planetModel.equals(((BasePlanetObject)o).planetModel);
+  }
+}
+
+
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/BaseXYZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/BaseXYZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/BaseXYZSolid.java
new file mode 100644
index 0000000..16b52cc
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/BaseXYZSolid.java
@@ -0,0 +1,167 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Base class of a family of 3D rectangles, bounded on six sides by X,Y,Z limits
+ *
+ * @lucene.internal
+ */
+public abstract class BaseXYZSolid extends BasePlanetObject implements XYZSolid {
+
+  /** Unit vector in x */
+  protected static final Vector xUnitVector = new Vector(1.0, 0.0, 0.0);
+  /** Unit vector in y */
+  protected static final Vector yUnitVector = new Vector(0.0, 1.0, 0.0);
+  /** Unit vector in z */
+  protected static final Vector zUnitVector = new Vector(0.0, 0.0, 1.0);
+  
+  /** Vertical plane normal to x unit vector passing through origin */
+  protected static final Plane xVerticalPlane = new Plane(0.0, 1.0, 0.0, 0.0);
+  /** Vertical plane normal to y unit vector passing through origin */
+  protected static final Plane yVerticalPlane = new Plane(1.0, 0.0, 0.0, 0.0);
+
+  /** Empty point vector */
+  protected static final GeoPoint[] EMPTY_POINTS = new GeoPoint[0];
+  
+  /**
+   * Base solid constructor.
+   *@param planetModel is the planet model.
+   */
+  public BaseXYZSolid(final PlanetModel planetModel) {
+    super(planetModel);
+  }
+  
+  /** Construct a single array from a number of individual arrays.
+   * @param pointArrays is the array of point arrays.
+   * @return the single unified array.
+   */
+  protected static GeoPoint[] glueTogether(final GeoPoint[]... pointArrays) {
+    int count = 0;
+    for (final GeoPoint[] pointArray : pointArrays) {
+      count += pointArray.length;
+    }
+    final GeoPoint[] rval = new GeoPoint[count];
+    count = 0;
+    for (final GeoPoint[] pointArray : pointArrays) {
+      for (final GeoPoint point : pointArray) {
+        rval[count++] = point;
+      }
+    }
+    return rval;
+  }
+  
+  @Override
+  public boolean isWithin(final Vector point) {
+    return isWithin(point.x, point.y, point.z);
+  }
+  
+  @Override
+  public abstract boolean isWithin(final double x, final double y, final double z);
+  
+  // Signals for relationship of edge points to shape
+  
+  /** All edgepoints inside shape */
+  protected final static int ALL_INSIDE = 0;
+  /** Some edgepoints inside shape */
+  protected final static int SOME_INSIDE = 1;
+  /** No edgepoints inside shape */
+  protected final static int NONE_INSIDE = 2;
+  /** No edgepoints at all (means a shape that is the whole world) */
+  protected final static int NO_EDGEPOINTS = 3;
+
+  /** Determine the relationship between this area and the provided
+   * shape's edgepoints.
+   *@param path is the shape.
+   *@return the relationship.
+   */
+  protected int isShapeInsideArea(final GeoShape path) {
+    final GeoPoint[] pathPoints = path.getEdgePoints();
+    if (pathPoints.length == 0)
+      return NO_EDGEPOINTS;
+    boolean foundOutside = false;
+    boolean foundInside = false;
+    for (final GeoPoint p : pathPoints) {
+      if (isWithin(p)) {
+        foundInside = true;
+      } else {
+        foundOutside = true;
+      }
+      if (foundInside && foundOutside) {
+        return SOME_INSIDE;
+      }
+    }
+    if (!foundInside && !foundOutside)
+      return NONE_INSIDE;
+    if (foundInside && !foundOutside)
+      return ALL_INSIDE;
+    if (foundOutside && !foundInside)
+      return NONE_INSIDE;
+    return SOME_INSIDE;
+  }
+
+  /** Determine the relationship between a shape and this area's
+   * edgepoints.
+   *@param path is the shape.
+   *@return the relationship.
+   */
+  protected int isAreaInsideShape(final GeoShape path) {
+    final GeoPoint[] edgePoints = getEdgePoints();
+    if (edgePoints.length == 0) {
+      return NO_EDGEPOINTS;
+    }
+    boolean foundOutside = false;
+    boolean foundInside = false;
+    for (final GeoPoint p : edgePoints) {
+      if (path.isWithin(p)) {
+        foundInside = true;
+      } else {
+        foundOutside = true;
+      }
+      if (foundInside && foundOutside) {
+        return SOME_INSIDE;
+      }
+    }
+    if (!foundInside && !foundOutside)
+      return NONE_INSIDE;
+    if (foundInside && !foundOutside)
+      return ALL_INSIDE;
+    if (foundOutside && !foundInside)
+      return NONE_INSIDE;
+    return SOME_INSIDE;
+  }
+
+  /** Get the edge points for this shape.
+   *@return the edge points.
+   */
+  protected abstract GeoPoint[] getEdgePoints();
+  
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof BaseXYZSolid))
+      return false;
+    BaseXYZSolid other = (BaseXYZSolid) o;
+    return super.equals(other);
+  }
+
+  @Override
+  public int hashCode() {
+    return super.hashCode();
+  }
+
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Bounds.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Bounds.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Bounds.java
new file mode 100755
index 0000000..4f7c663
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Bounds.java
@@ -0,0 +1,113 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * An interface for accumulating bounds information.
+ * The bounds object is initially empty.  Bounding points
+ * are then applied by supplying (x,y,z) tuples.  It is also
+ * possible to indicate the following edge cases:
+ * (1) No longitude bound possible
+ * (2) No upper latitude bound possible
+ * (3) No lower latitude bound possible
+ * When any of these have been applied, further application of
+ * points cannot override that decision.
+ *
+ * @lucene.experimental
+ */
+public interface Bounds {
+
+  /** Add a general plane to the bounds description.
+   *@param planetModel is the planet model.
+   *@param plane is the plane.
+   *@param bounds are the membership bounds for points along the arc.
+   */
+  public Bounds addPlane(final PlanetModel planetModel, final Plane plane, final Membership... bounds);
+  
+  /** Add a horizontal plane to the bounds description.
+   * This method should EITHER use the supplied latitude, OR use the supplied
+   * plane, depending on what is most efficient.
+   *@param planetModel is the planet model.
+   *@param latitude is the latitude.
+   *@param horizontalPlane is the plane.
+   *@param bounds are the constraints on the plane.
+   *@return updated Bounds object.
+   */
+  public Bounds addHorizontalPlane(final PlanetModel planetModel,
+    final double latitude,
+    final Plane horizontalPlane,
+    final Membership... bounds);
+    
+  /** Add a vertical plane to the bounds description.
+   * This method should EITHER use the supplied longitude, OR use the supplied
+   * plane, depending on what is most efficient.
+   *@param planetModel is the planet model.
+   *@param longitude is the longitude.
+   *@param verticalPlane is the plane.
+   *@param bounds are the constraints on the plane.
+   *@return updated Bounds object.
+   */
+  public Bounds addVerticalPlane(final PlanetModel planetModel,
+    final double longitude,
+    final Plane verticalPlane,
+    final Membership... bounds);
+
+  /** Add a single point.
+   *@param point is the point.
+   *@return the updated Bounds object.
+   */
+  public Bounds addPoint(final GeoPoint point);
+
+  /** Add an X value.
+   *@param point is the point to take the x value from.
+   *@return the updated object.
+   */
+  public Bounds addXValue(final GeoPoint point);
+
+  /** Add a Y value.
+   *@param point is the point to take the y value from.
+   *@return the updated object.
+   */
+  public Bounds addYValue(final GeoPoint point);
+
+  /** Add a Z value.
+   *@param point is the point to take the z value from.
+   *@return the updated object.
+   */
+  public Bounds addZValue(final GeoPoint point);
+  
+  /** Signal that the shape exceeds Math.PI in longitude.
+   *@return the updated Bounds object.
+   */
+  public Bounds isWide();
+  
+  /** Signal that there is no longitude bound.
+   *@return the updated Bounds object.
+   */
+  public Bounds noLongitudeBound();
+
+  /** Signal that there is no top latitude bound.
+   *@return the updated Bounds object.
+   */
+  public Bounds noTopLatitudeBound();
+
+  /** Signal that there is no bottom latitude bound.
+   *@return the updated Bounds object.
+   */
+  public Bounds noBottomLatitudeBound();
+  
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/DistanceStyle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/DistanceStyle.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/DistanceStyle.java
new file mode 100644
index 0000000..8c8658d
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/DistanceStyle.java
@@ -0,0 +1,83 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Distance computation styles, supporting various ways of computing
+ * distance to shapes.
+ *
+ * @lucene.experimental
+ */
+public interface DistanceStyle {
+
+  // convenient access to built-in styles:
+
+  /** Arc distance calculator */
+  public static final ArcDistance ARC = ArcDistance.INSTANCE;
+  /** Linear distance calculator */
+  public static final LinearDistance LINEAR = LinearDistance.INSTANCE;
+  /** Linear distance squared calculator */
+  public static final LinearSquaredDistance LINEAR_SQUARED = LinearSquaredDistance.INSTANCE;
+  /** Normal distance calculator */
+  public static final NormalDistance NORMAL = NormalDistance.INSTANCE;
+  /** Normal distance squared calculator */
+  public static final NormalSquaredDistance NORMAL_SQUARED = NormalSquaredDistance.INSTANCE;
+
+  /** Compute the distance from a point to another point.
+   * @param point1 Starting point
+   * @param point2 Final point
+   * @return the distance
+   */
+  public default double computeDistance(final GeoPoint point1, final GeoPoint point2) {
+    return computeDistance(point1, point2.x, point2.y, point2.z);
+  }
+  
+  /** Compute the distance from a point to another point.
+   * @param point1 Starting point
+   * @param x2 Final point x
+   * @param y2 Final point y
+   * @param z2 Final point z
+   * @return the distance
+   */
+  public double computeDistance(final GeoPoint point1, final double x2, final double y2, final double z2);
+
+  /** Compute the distance from a plane to a point.
+   * @param planetModel The planet model
+   * @param plane The plane
+   * @param point The point
+   * @param bounds are the plane bounds
+   * @return the distance
+   */
+  public default double computeDistance(final PlanetModel planetModel, final Plane plane, final GeoPoint point,
+                                        final Membership... bounds) {
+    return computeDistance(planetModel, plane, point.x, point.y, point.z, bounds);
+  }
+  
+  /** Compute the distance from a plane to a point.
+   * @param planetModel The planet model
+   * @param plane The plane
+   * @param x The point x
+   * @param y The point y
+   * @param z The point z
+   * @param bounds are the plane bounds
+   * @return the distance
+   */
+  public double computeDistance(final PlanetModel planetModel, final Plane plane, final double x, final double y, final double z, final Membership... bounds);
+
+}
+
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoArea.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoArea.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoArea.java
new file mode 100755
index 0000000..5a6db0d
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoArea.java
@@ -0,0 +1,67 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * A GeoArea represents a standard 2-D breakdown of a part of sphere.  It can
+ * be bounded in latitude, or bounded in both latitude and longitude, or not
+ * bounded at all.  The purpose of the interface is to describe bounding shapes used for
+ * computation of geo hashes.
+ *
+ * @lucene.experimental
+ */
+public interface GeoArea extends Membership {
+  // Since we don't know what each GeoArea's constraints are,
+  // we put the onus on the GeoArea implementation to do the right thing.
+  // This will, of course, rely heavily on methods provided by
+  // the underlying GeoShape class.
+
+  // Relationship values for "getRelationship()"
+  
+  /** The referenced shape CONTAINS this area */
+  public static final int CONTAINS = 0;
+  /** The referenced shape IS WITHIN this area */
+  public static final int WITHIN = 1;
+  /** The referenced shape OVERLAPS this area */
+  public static final int OVERLAPS = 2;
+  /** The referenced shape has no relation to this area */
+  public static final int DISJOINT = 3;
+
+  /**
+   * Find the spatial relationship between a shape and the current geo area.
+   * Note: return value is how the GeoShape relates to the GeoArea, not the
+   * other way around. For example, if this GeoArea is entirely within the
+   * shape, then CONTAINS should be returned.  If the shape is entirely enclosed
+   * by this GeoArea, then WITHIN should be returned.
+   *
+   * It is permissible to return OVERLAPS instead of WITHIN if the shape
+   * intersects with the area at even a single point.  So, a circle inscribed in
+   * a rectangle could return either OVERLAPS or WITHIN, depending on
+   * implementation.  It is not permissible to return CONTAINS or DISJOINT
+   * in this circumstance, however.
+   *
+   * Similarly, it is permissible to return OVERLAPS instead of CONTAINS
+   * under conditions where the shape consists of multiple independent overlapping
+   * subshapes, and the area overlaps one of the subshapes.  It is not permissible
+   * to return WITHIN or DISJOINT in this circumstance, however.
+   *
+   * @param shape is the shape to consider.
+   * @return the relationship, from the perspective of the shape.
+   */
+  public int getRelationship(GeoShape shape);
+}
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoAreaFactory.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoAreaFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoAreaFactory.java
new file mode 100755
index 0000000..0c3caa9
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoAreaFactory.java
@@ -0,0 +1,55 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Factory for {@link GeoArea}.
+ *
+ * @lucene.experimental
+ */
+public class GeoAreaFactory {
+  private GeoAreaFactory() {
+  }
+
+  /**
+   * Create a GeoArea of the right kind given the specified bounds.
+   * @param planetModel is the planet model
+   * @param topLat    is the top latitude
+   * @param bottomLat is the bottom latitude
+   * @param leftLon   is the left longitude
+   * @param rightLon  is the right longitude
+   * @return a GeoArea corresponding to what was specified.
+   */
+  public static GeoArea makeGeoArea(final PlanetModel planetModel, final double topLat, final double bottomLat, final double leftLon, final double rightLon) {
+    return GeoBBoxFactory.makeGeoBBox(planetModel, topLat, bottomLat, leftLon, rightLon);
+  }
+
+  /**
+   * Create a GeoArea of the right kind given (x,y,z) bounds.
+   * @param planetModel is the planet model
+   * @param minX is the min X boundary
+   * @param maxX is the max X boundary
+   * @param minY is the min Y boundary
+   * @param maxY is the max Y boundary
+   * @param minZ is the min Z boundary
+   * @param maxZ is the max Z boundary
+   */
+  public static GeoArea makeGeoArea(final PlanetModel planetModel, final double minX, final double maxX, final double minY, final double maxY, final double minZ, final double maxZ) {
+    return XYZSolidFactory.makeXYZSolid(planetModel, minX, maxX, minY, maxY, minZ, maxZ);
+  }
+  
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBBox.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBBox.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBBox.java
new file mode 100755
index 0000000..0ae2425
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBBox.java
@@ -0,0 +1,36 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * All bounding box shapes have this interface in common.
+ * This describes methods that bounding boxes have above and beyond
+ * GeoMembershipShape's.
+ *
+ * @lucene.experimental
+ */
+public interface GeoBBox extends GeoMembershipShape, GeoSizeable, GeoArea {
+
+  /**
+   * Expand box by specified angle.
+   *
+   * @param angle is the angle amount to expand the GeoBBox by.
+   * @return a new GeoBBox.
+   */
+  public GeoBBox expand(double angle);
+
+}


[08/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 0093e26)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoLongitudeSlice.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoLongitudeSlice.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoLongitudeSlice.java
new file mode 100755
index 0000000..458cf8b
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoLongitudeSlice.java
@@ -0,0 +1,204 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Bounding box limited on left and right.
+ * The left-right maximum extent for this shape is PI; for anything larger, use
+ * {@link GeoWideLongitudeSlice}.
+ *
+ * @lucene.internal
+ */
+public class GeoLongitudeSlice extends GeoBaseBBox {
+  /** The left longitude of the slice */
+  protected final double leftLon;
+  /** The right longitude of the slice */
+  protected final double rightLon;
+  /** The left plane of the slice */
+  protected final SidedPlane leftPlane;
+  /** The right plane of the slice */
+  protected final SidedPlane rightPlane;
+  /** The notable points for the slice (north and south poles) */
+  protected final GeoPoint[] planePoints;
+  /** The center point of the slice */
+  protected final GeoPoint centerPoint;
+  /** A point on the edge of the slice */
+  protected final GeoPoint[] edgePoints;
+
+  /**
+   * Accepts only values in the following ranges: lon: {@code -PI -> PI}
+   *@param planetModel is the planet model.
+   *@param leftLon is the left longitude of the slice.
+   *@param rightLon is the right longitude of the slice.
+   */
+  public GeoLongitudeSlice(final PlanetModel planetModel, final double leftLon, double rightLon) {
+    super(planetModel);
+    // Argument checking
+    if (leftLon < -Math.PI || leftLon > Math.PI)
+      throw new IllegalArgumentException("Left longitude out of range");
+    if (rightLon < -Math.PI || rightLon > Math.PI)
+      throw new IllegalArgumentException("Right longitude out of range");
+    double extent = rightLon - leftLon;
+    if (extent < 0.0) {
+      extent += 2.0 * Math.PI;
+    }
+    if (extent > Math.PI)
+      throw new IllegalArgumentException("Width of rectangle too great");
+
+    this.leftLon = leftLon;
+    this.rightLon = rightLon;
+
+    final double sinLeftLon = Math.sin(leftLon);
+    final double cosLeftLon = Math.cos(leftLon);
+    final double sinRightLon = Math.sin(rightLon);
+    final double cosRightLon = Math.cos(rightLon);
+
+    // Normalize
+    while (leftLon > rightLon) {
+      rightLon += Math.PI * 2.0;
+    }
+    final double middleLon = (leftLon + rightLon) * 0.5;
+    this.centerPoint = new GeoPoint(planetModel, 0.0, middleLon);
+
+    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
+    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
+
+    this.planePoints = new GeoPoint[]{planetModel.NORTH_POLE, planetModel.SOUTH_POLE};
+    this.edgePoints = new GeoPoint[]{planetModel.NORTH_POLE};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    // Figuring out when we escalate to a special case requires some prefiguring
+    double currentLonSpan = rightLon - leftLon;
+    if (currentLonSpan < 0.0)
+      currentLonSpan += Math.PI * 2.0;
+    double newLeftLon = leftLon - angle;
+    double newRightLon = rightLon + angle;
+    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
+      newLeftLon = -Math.PI;
+      newRightLon = Math.PI;
+    }
+    return GeoBBoxFactory.makeGeoBBox(planetModel, Math.PI * 0.5, -Math.PI * 0.5, newLeftLon, newRightLon);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return leftPlane.isWithin(x, y, z) &&
+        rightPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public double getRadius() {
+    // Compute the extent and divide by two
+    double extent = rightLon - leftLon;
+    if (extent < 0.0)
+      extent += Math.PI * 2.0;
+    return Math.max(Math.PI * 0.5, extent * 0.5);
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    return centerPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return p.intersects(planetModel, leftPlane, notablePoints, planePoints, bounds, rightPlane) ||
+        p.intersects(planetModel, rightPlane, notablePoints, planePoints, bounds, leftPlane);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds
+      .addVerticalPlane(planetModel, leftLon, leftPlane, rightPlane)
+      .addVerticalPlane(planetModel, rightLon, rightPlane, leftPlane)
+      .addPoint(planetModel.NORTH_POLE)
+      .addPoint(planetModel.SOUTH_POLE);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    final int insideRectangle = isShapeInsideBBox(path);
+    if (insideRectangle == SOME_INSIDE)
+      return OVERLAPS;
+
+    final boolean insideShape = path.isWithin(planetModel.NORTH_POLE);
+
+    if (insideRectangle == ALL_INSIDE && insideShape)
+      return OVERLAPS;
+
+    if (path.intersects(leftPlane, planePoints, rightPlane) ||
+        path.intersects(rightPlane, planePoints, leftPlane)) {
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      return WITHIN;
+    }
+
+    if (insideShape) {
+      return CONTAINS;
+    }
+
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, rightPlane);
+    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, leftPlane);
+    
+    final double northDistance = distanceStyle.computeDistance(planetModel.NORTH_POLE, x,y,z);
+    final double southDistance = distanceStyle.computeDistance(planetModel.SOUTH_POLE, x,y,z);
+    
+    return
+      Math.min(
+        Math.min(northDistance, southDistance),
+        Math.min(leftDistance, rightDistance));
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoLongitudeSlice))
+      return false;
+    GeoLongitudeSlice other = (GeoLongitudeSlice) o;
+    return super.equals(other) && other.leftLon == leftLon && other.rightLon == rightLon;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    long temp = Double.doubleToLongBits(leftLon);
+    result = 31 * result + (int) (temp ^ (temp >>> 32));
+    temp = Double.doubleToLongBits(rightLon);
+    result = 31 * result + (int) (temp ^ (temp >>> 32));
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoLongitudeSlice: {planetmodel="+planetModel+", leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
+  }
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoMembershipShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoMembershipShape.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoMembershipShape.java
new file mode 100755
index 0000000..2c47971
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoMembershipShape.java
@@ -0,0 +1,27 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Membership shapes have capabilities of both geohashing and membership
+ * determination.
+ *
+ * @lucene.experimental
+ */
+public interface GeoMembershipShape extends GeoShape, GeoOutsideDistance, Membership {
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoNorthLatitudeZone.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoNorthLatitudeZone.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoNorthLatitudeZone.java
new file mode 100644
index 0000000..2c94061
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoNorthLatitudeZone.java
@@ -0,0 +1,165 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * This GeoBBox represents an area rectangle limited only in south latitude.
+ *
+ * @lucene.internal
+ */
+public class GeoNorthLatitudeZone extends GeoBaseBBox {
+  /** The bottom latitude of the zone */
+  protected final double bottomLat;
+  /** Cosine of the bottom latitude of the zone */
+  protected final double cosBottomLat;
+  /** The bottom plane of the zone */
+  protected final SidedPlane bottomPlane;
+  /** An interior point of the zone */
+  protected final GeoPoint interiorPoint;
+  /** Notable points: none */
+  protected final static GeoPoint[] planePoints = new GeoPoint[0];
+  /** A point on the bottom boundary */
+  protected final GeoPoint bottomBoundaryPoint;
+  /** A reference to the point on the boundary */
+  protected final GeoPoint[] edgePoints;
+
+  /** Constructor.
+   *@param planetModel is the planet model.
+   *@param bottomLat is the bottom latitude.
+   */
+  public GeoNorthLatitudeZone(final PlanetModel planetModel, final double bottomLat) {
+    super(planetModel);
+    this.bottomLat = bottomLat;
+
+    final double sinBottomLat = Math.sin(bottomLat);
+    this.cosBottomLat = Math.cos(bottomLat);
+
+    // Compute an interior point.  Pick one whose lat is between top and bottom.
+    final double middleLat = (Math.PI * 0.5 + bottomLat) * 0.5;
+    final double sinMiddleLat = Math.sin(middleLat);
+    this.interiorPoint = new GeoPoint(planetModel, sinMiddleLat, 0.0, Math.sqrt(1.0 - sinMiddleLat * sinMiddleLat), 1.0);
+    this.bottomBoundaryPoint = new GeoPoint(planetModel, sinBottomLat, 0.0, Math.sqrt(1.0 - sinBottomLat * sinBottomLat), 1.0);
+
+    this.bottomPlane = new SidedPlane(interiorPoint, planetModel, sinBottomLat);
+
+    this.edgePoints = new GeoPoint[]{bottomBoundaryPoint};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    final double newTopLat = Math.PI * 0.5;
+    final double newBottomLat = bottomLat - angle;
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, -Math.PI, Math.PI);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return
+        bottomPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public double getRadius() {
+    // This is a bit tricky.  I guess we should interpret this as meaning the angle of a circle that
+    // would contain all the bounding box points, when starting in the "center".
+    if (bottomLat < 0.0)
+      return Math.PI;
+    double maxCosLat = cosBottomLat;
+    return maxCosLat * Math.PI;
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    return interiorPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return
+        p.intersects(planetModel, bottomPlane, notablePoints, planePoints, bounds);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds
+      .addHorizontalPlane(planetModel, bottomLat, bottomPlane);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    final int insideRectangle = isShapeInsideBBox(path);
+    if (insideRectangle == SOME_INSIDE)
+      return OVERLAPS;
+
+    final boolean insideShape = path.isWithin(bottomBoundaryPoint);
+
+    if (insideRectangle == ALL_INSIDE && insideShape)
+      return OVERLAPS;
+
+    // Second, the shortcut of seeing whether endpoints are in/out is not going to
+    // work with no area endpoints.  So we rely entirely on intersections.
+
+    if (path.intersects(bottomPlane, planePoints))
+      return OVERLAPS;
+
+    // There is another case for latitude zones only.  This is when the boundaries of the shape all fit
+    // within the zone, but the shape includes areas outside the zone crossing a pole.
+    // In this case, the above "overlaps" check is insufficient.  We also need to check a point on either boundary
+    // whether it is within the shape.  If both such points are within, then CONTAINS is the right answer.  If
+    // one such point is within, then OVERLAPS is the right answer.
+
+    if (insideShape)
+      return CONTAINS;
+
+    if (insideRectangle == ALL_INSIDE)
+      return WITHIN;
+
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    return distanceStyle.computeDistance(planetModel, bottomPlane, x,y,z);
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoNorthLatitudeZone))
+      return false;
+    GeoNorthLatitudeZone other = (GeoNorthLatitudeZone) o;
+    return super.equals(other) && other.bottomBoundaryPoint.equals(bottomBoundaryPoint);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + bottomBoundaryPoint.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoNorthLatitudeZone: {planetmodel="+planetModel+", bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + ")}";
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoNorthRectangle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoNorthRectangle.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoNorthRectangle.java
new file mode 100644
index 0000000..a2b6f1b
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoNorthRectangle.java
@@ -0,0 +1,263 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Bounding box limited on three sides (bottom lat, left lon, right lon), including
+ * the north pole.
+ * The left-right maximum extent for this shape is PI; for anything larger, use
+ * {@link GeoWideNorthRectangle}.
+ *
+ * @lucene.internal
+ */
+public class GeoNorthRectangle extends GeoBaseBBox {
+  /** The bottom latitude of the rectangle */
+  protected final double bottomLat;
+  /** The left longitude */
+  protected final double leftLon;
+  /** The right longitude */
+  protected final double rightLon;
+  /** Cosine of the middle latitude */
+  protected final double cosMiddleLat;
+  /** Lower right hand corner point */
+  protected final GeoPoint LRHC;
+  /** Lower left hand corner point */
+  protected final GeoPoint LLHC;
+  /** Bottom edge plane */
+  protected final SidedPlane bottomPlane;
+  /** Left-side plane */
+  protected final SidedPlane leftPlane;
+  /** Right-side plane */
+  protected final SidedPlane rightPlane;
+  /** Bottom plane notable points */
+  protected final GeoPoint[] bottomPlanePoints;
+  /** Left plane notable points */
+  protected final GeoPoint[] leftPlanePoints;
+  /** Right plane notable points */
+  protected final GeoPoint[] rightPlanePoints;
+  /** Center point */
+  protected final GeoPoint centerPoint;
+  /** A point on the edge */
+  protected final GeoPoint[] edgePoints;
+
+  /**
+   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
+   *@param planetModel is the planet model.
+   *@param bottomLat is the bottom latitude.
+   *@param leftLon is the left longitude.
+   *@param rightLon is the right longitude.
+   */
+  public GeoNorthRectangle(final PlanetModel planetModel, final double bottomLat, final double leftLon, double rightLon) {
+    super(planetModel);
+    // Argument checking
+    if (bottomLat > Math.PI * 0.5 || bottomLat < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Bottom latitude out of range");
+    if (leftLon < -Math.PI || leftLon > Math.PI)
+      throw new IllegalArgumentException("Left longitude out of range");
+    if (rightLon < -Math.PI || rightLon > Math.PI)
+      throw new IllegalArgumentException("Right longitude out of range");
+    double extent = rightLon - leftLon;
+    if (extent < 0.0) {
+      extent += 2.0 * Math.PI;
+    }
+    if (extent > Math.PI)
+      throw new IllegalArgumentException("Width of rectangle too great");
+
+    this.bottomLat = bottomLat;
+    this.leftLon = leftLon;
+    this.rightLon = rightLon;
+
+    final double sinBottomLat = Math.sin(bottomLat);
+    final double cosBottomLat = Math.cos(bottomLat);
+    final double sinLeftLon = Math.sin(leftLon);
+    final double cosLeftLon = Math.cos(leftLon);
+    final double sinRightLon = Math.sin(rightLon);
+    final double cosRightLon = Math.cos(rightLon);
+
+    // Now build the points
+    this.LRHC = new GeoPoint(planetModel, sinBottomLat, sinRightLon, cosBottomLat, cosRightLon, bottomLat, rightLon);
+    this.LLHC = new GeoPoint(planetModel, sinBottomLat, sinLeftLon, cosBottomLat, cosLeftLon, bottomLat, leftLon);
+
+    final double middleLat = (Math.PI * 0.5 + bottomLat) * 0.5;
+    final double sinMiddleLat = Math.sin(middleLat);
+    this.cosMiddleLat = Math.cos(middleLat);
+    // Normalize
+    while (leftLon > rightLon) {
+      rightLon += Math.PI * 2.0;
+    }
+    final double middleLon = (leftLon + rightLon) * 0.5;
+    final double sinMiddleLon = Math.sin(middleLon);
+    final double cosMiddleLon = Math.cos(middleLon);
+
+    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinMiddleLon, cosMiddleLat, cosMiddleLon);
+
+    this.bottomPlane = new SidedPlane(centerPoint, planetModel, sinBottomLat);
+    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
+    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
+
+    this.bottomPlanePoints = new GeoPoint[]{LLHC, LRHC};
+    this.leftPlanePoints = new GeoPoint[]{planetModel.NORTH_POLE, LLHC};
+    this.rightPlanePoints = new GeoPoint[]{planetModel.NORTH_POLE, LRHC};
+
+    this.edgePoints = new GeoPoint[]{planetModel.NORTH_POLE};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    final double newTopLat = Math.PI * 0.5;
+    final double newBottomLat = bottomLat - angle;
+    // Figuring out when we escalate to a special case requires some prefiguring
+    double currentLonSpan = rightLon - leftLon;
+    if (currentLonSpan < 0.0)
+      currentLonSpan += Math.PI * 2.0;
+    double newLeftLon = leftLon - angle;
+    double newRightLon = rightLon + angle;
+    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
+      newLeftLon = -Math.PI;
+      newRightLon = Math.PI;
+    }
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return
+        bottomPlane.isWithin(x, y, z) &&
+            leftPlane.isWithin(x, y, z) &&
+            rightPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public double getRadius() {
+    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
+    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
+    // the distance to the right or left edge from the center.
+    final double centerAngle = (rightLon - (rightLon + leftLon) * 0.5) * cosMiddleLat;
+    final double bottomAngle = centerPoint.arcDistance(LLHC);
+    return Math.max(centerAngle, bottomAngle);
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  /**
+   * Returns the center of a circle into which the area will be inscribed.
+   *
+   * @return the center.
+   */
+  @Override
+  public GeoPoint getCenter() {
+    return centerPoint;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return
+        p.intersects(planetModel, bottomPlane, notablePoints, bottomPlanePoints, bounds, leftPlane, rightPlane) ||
+            p.intersects(planetModel, leftPlane, notablePoints, leftPlanePoints, bounds, rightPlane, bottomPlane) ||
+            p.intersects(planetModel, rightPlane, notablePoints, rightPlanePoints, bounds, leftPlane, bottomPlane);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds
+      .addHorizontalPlane(planetModel, bottomLat, bottomPlane, leftPlane, rightPlane)
+      .addVerticalPlane(planetModel, leftLon, leftPlane, bottomPlane, rightPlane)
+      .addVerticalPlane(planetModel, rightLon, rightPlane, bottomPlane, leftPlane)
+      .addPoint(LLHC).addPoint(LRHC).addPoint(planetModel.NORTH_POLE);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    //System.err.println(this+" getrelationship with "+path);
+    final int insideRectangle = isShapeInsideBBox(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some inside");
+      return OVERLAPS;
+    }
+
+    final boolean insideShape = path.isWithin(planetModel.NORTH_POLE);
+
+    if (insideRectangle == ALL_INSIDE && insideShape) {
+      //System.err.println(" inside of each other");
+      return OVERLAPS;
+    }
+
+    if (
+        path.intersects(bottomPlane, bottomPlanePoints, leftPlane, rightPlane) ||
+            path.intersects(leftPlane, leftPlanePoints, bottomPlane, rightPlane) ||
+            path.intersects(rightPlane, rightPlanePoints, leftPlane, bottomPlane)) {
+      //System.err.println(" edges intersect");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      //System.err.println(" shape inside rectangle");
+      return WITHIN;
+    }
+
+    if (insideShape) {
+      //System.err.println(" shape contains rectangle");
+      return CONTAINS;
+    }
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    final double bottomDistance = distanceStyle.computeDistance(planetModel, bottomPlane, x,y,z, leftPlane, rightPlane);
+    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, rightPlane, bottomPlane);
+    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, leftPlane, bottomPlane);
+    
+    final double LRHCDistance = distanceStyle.computeDistance(LRHC, x,y,z);
+    final double LLHCDistance = distanceStyle.computeDistance(LLHC, x,y,z);
+    
+    return
+      Math.min(
+        bottomDistance,
+        Math.min(
+          Math.min(leftDistance, rightDistance),
+          Math.min(LRHCDistance, LLHCDistance)));
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoNorthRectangle))
+      return false;
+    GeoNorthRectangle other = (GeoNorthRectangle) o;
+    return super.equals(other) && other.LLHC.equals(LLHC) && other.LRHC.equals(LRHC);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + LLHC.hashCode();
+    result = 31 * result + LRHC.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoNorthRectangle: {planetmodel="+planetModel+", bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
+  }
+}
+  
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoOutsideDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoOutsideDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoOutsideDistance.java
new file mode 100644
index 0000000..717854c
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoOutsideDistance.java
@@ -0,0 +1,55 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Implemented by Geo3D shapes that can compute the distance from a point to the closest outside edge.
+ *
+ * @lucene.experimental
+ */
+public interface GeoOutsideDistance extends Membership {
+  
+  // The following methods compute distances from the shape to a point
+  // expected to be OUTSIDE the shape.  Typically a value of 0.0
+  // is returned for points that happen to be within the shape.
+  
+  /**
+   * Compute this shape's distance to the GeoPoint.
+   * A return value of 0.0 should be returned for
+   * points inside of the shape.
+   * @param distanceStyle is the distance style.
+   * @param point is the point to compute the distance to.
+   * @return the distance.
+   */
+  public default double computeOutsideDistance(final DistanceStyle distanceStyle, final GeoPoint point) {
+    return computeOutsideDistance(distanceStyle, point.x, point.y, point.z);
+  }
+
+  /**
+   * Compute this shape's distance to the GeoPoint.
+   * A return value of 0.0 should be returned for
+   * points inside of the shape.
+   * @param distanceStyle is the distance style.
+   * @param x is the point's unit x coordinate (using U.S. convention).
+   * @param y is the point's unit y coordinate (using U.S. convention).
+   * @param z is the point's unit z coordinate (using U.S. convention).
+   * @return the distance.
+   */
+  public double computeOutsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z);
+
+}
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPath.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPath.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPath.java
new file mode 100755
index 0000000..a5b8b9b
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPath.java
@@ -0,0 +1,797 @@
+/*
+ * 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.spatial3d.geom;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * GeoShape representing a path across the surface of the globe,
+ * with a specified half-width.  Path is described by a series of points.
+ * Distances are measured from the starting point along the path, and then at right
+ * angles to the path.
+ *
+ * @lucene.experimental
+ */
+public class GeoPath extends GeoBaseDistanceShape {
+  /** The cutoff angle (width) */
+  protected final double cutoffAngle;
+
+  /** Sine of cutoff angle */
+  protected final double sinAngle;
+  /** Cosine of cutoff angle */
+  protected final double cosAngle;
+
+  /** The original list of path points */
+  protected final List<GeoPoint> points = new ArrayList<GeoPoint>();
+  
+  /** A list of SegmentEndpoints */
+  protected List<SegmentEndpoint> endPoints;
+  /** A list of PathSegments */
+  protected List<PathSegment> segments;
+
+  /** A point on the edge */
+  protected GeoPoint[] edgePoints;
+
+  /** Set to true if path has been completely constructed */
+  protected boolean isDone = false;
+  
+  /** Constructor.
+   *@param planetModel is the planet model.
+   *@param maxCutoffAngle is the width of the path, measured as an angle.
+   *@param pathPoints are the points in the path.
+   */
+  public GeoPath(final PlanetModel planetModel, final double maxCutoffAngle, final GeoPoint[] pathPoints) {
+    this(planetModel, maxCutoffAngle);
+    Collections.addAll(points, pathPoints);
+    done();
+  }
+  
+  /** Piece-wise constructor.  Use in conjunction with addPoint() and done().
+   *@param planetModel is the planet model.
+   *@param maxCutoffAngle is the width of the path, measured as an angle.
+   */
+  public GeoPath(final PlanetModel planetModel, final double maxCutoffAngle) {
+    super(planetModel);
+    if (maxCutoffAngle <= 0.0 || maxCutoffAngle > Math.PI * 0.5)
+      throw new IllegalArgumentException("Cutoff angle out of bounds");
+    this.cutoffAngle = maxCutoffAngle;
+    this.cosAngle = Math.cos(maxCutoffAngle);
+    this.sinAngle = Math.sin(maxCutoffAngle);
+  }
+
+  /** Add a point to the path.
+   *@param lat is the latitude of the point.
+   *@param lon is the longitude of the point.
+   */
+  public void addPoint(final double lat, final double lon) {
+    if (isDone)
+      throw new IllegalStateException("Can't call addPoint() if done() already called");
+    points.add(new GeoPoint(planetModel, lat, lon));
+  }
+  
+  /** Complete the path.
+   */
+  public void done() {
+    if (isDone)
+      throw new IllegalStateException("Can't call done() twice");
+    if (points.size() == 0)
+      throw new IllegalArgumentException("Path must have at least one point");
+    isDone = true;
+
+    endPoints = new ArrayList<>(points.size());
+    segments = new ArrayList<>(points.size());
+    // Compute an offset to use for all segments.  This will be based on the minimum magnitude of
+    // the entire ellipsoid.
+    final double cutoffOffset = this.sinAngle * planetModel.getMinimumMagnitude();
+    
+    // First, build all segments.  We'll then go back and build corresponding segment endpoints.
+    GeoPoint lastPoint = null;
+    for (final GeoPoint end : points) {
+      if (lastPoint != null) {
+        final Plane normalizedConnectingPlane = new Plane(lastPoint, end);
+        if (normalizedConnectingPlane == null) {
+          continue;
+        }
+        segments.add(new PathSegment(planetModel, lastPoint, end, normalizedConnectingPlane, cutoffOffset));
+      }
+      lastPoint = end;
+    }
+    
+    if (segments.size() == 0) {
+      // Simple circle
+      double lat = points.get(0).getLatitude();
+      double lon = points.get(0).getLongitude();
+      // Compute two points on the circle, with the right angle from the center.  We'll use these
+      // to obtain the perpendicular plane to the circle.
+      double upperLat = lat + cutoffAngle;
+      double upperLon = lon;
+      if (upperLat > Math.PI * 0.5) {
+        upperLon += Math.PI;
+        if (upperLon > Math.PI)
+          upperLon -= 2.0 * Math.PI;
+        upperLat = Math.PI - upperLat;
+      }
+      double lowerLat = lat - cutoffAngle;
+      double lowerLon = lon;
+      if (lowerLat < -Math.PI * 0.5) {
+        lowerLon += Math.PI;
+        if (lowerLon > Math.PI)
+          lowerLon -= 2.0 * Math.PI;
+        lowerLat = -Math.PI - lowerLat;
+      }
+      final GeoPoint upperPoint = new GeoPoint(planetModel, upperLat, upperLon);
+      final GeoPoint lowerPoint = new GeoPoint(planetModel, lowerLat, lowerLon);
+      final GeoPoint point = points.get(0);
+      
+      // Construct normal plane
+      final Plane normalPlane = Plane.constructNormalizedZPlane(upperPoint, lowerPoint, point);
+
+      final SegmentEndpoint onlyEndpoint = new SegmentEndpoint(point, normalPlane, upperPoint, lowerPoint);
+      endPoints.add(onlyEndpoint);
+      this.edgePoints = new GeoPoint[]{onlyEndpoint.circlePlane.getSampleIntersectionPoint(planetModel, normalPlane)};
+      return;
+    }
+    
+    // Create segment endpoints.  Use an appropriate constructor for the start and end of the path.
+    for (int i = 0; i < segments.size(); i++) {
+      final PathSegment currentSegment = segments.get(i);
+      
+      if (i == 0) {
+        // Starting endpoint
+        final SegmentEndpoint startEndpoint = new SegmentEndpoint(currentSegment.start, 
+          currentSegment.startCutoffPlane, currentSegment.ULHC, currentSegment.LLHC);
+        endPoints.add(startEndpoint);
+        this.edgePoints = new GeoPoint[]{currentSegment.ULHC};
+        continue;
+      }
+      
+      // General intersection case
+      final PathSegment prevSegment = segments.get(i-1);
+      // We construct four separate planes, and evaluate which one includes all interior points with least overlap
+      final SidedPlane candidate1 = SidedPlane.constructNormalizedThreePointSidedPlane(currentSegment.start, prevSegment.URHC, currentSegment.ULHC, currentSegment.LLHC);
+      final SidedPlane candidate2 = SidedPlane.constructNormalizedThreePointSidedPlane(currentSegment.start, currentSegment.ULHC, currentSegment.LLHC, prevSegment.LRHC);
+      final SidedPlane candidate3 = SidedPlane.constructNormalizedThreePointSidedPlane(currentSegment.start, currentSegment.LLHC, prevSegment.LRHC, prevSegment.URHC);
+      final SidedPlane candidate4 = SidedPlane.constructNormalizedThreePointSidedPlane(currentSegment.start, prevSegment.LRHC, prevSegment.URHC, currentSegment.ULHC);
+
+      if (candidate1 == null && candidate2 == null && candidate3 == null && candidate4 == null) {
+        // The planes are identical.  We wouldn't need a circle at all except for the possibility of
+        // backing up, which is hard to detect here.
+        final SegmentEndpoint midEndpoint = new SegmentEndpoint(currentSegment.start, 
+          prevSegment.endCutoffPlane, currentSegment.startCutoffPlane, currentSegment.ULHC, currentSegment.LLHC);
+        //don't need a circle at all.  Special constructor...
+        endPoints.add(midEndpoint);
+      } else {
+        endPoints.add(new SegmentEndpoint(currentSegment.start,
+          prevSegment.endCutoffPlane, currentSegment.startCutoffPlane,
+          prevSegment.URHC, prevSegment.LRHC,
+          currentSegment.ULHC, currentSegment.LLHC,
+          candidate1, candidate2, candidate3, candidate4));
+      }
+    }
+    // Do final endpoint
+    final PathSegment lastSegment = segments.get(segments.size()-1);
+    endPoints.add(new SegmentEndpoint(lastSegment.end,
+      lastSegment.endCutoffPlane, lastSegment.URHC, lastSegment.LRHC));
+
+  }
+
+  @Override
+  protected double distance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    // Algorithm:
+    // (1) If the point is within any of the segments along the path, return that value.
+    // (2) If the point is within any of the segment end circles along the path, return that value.
+    double currentDistance = 0.0;
+    for (PathSegment segment : segments) {
+      double distance = segment.pathDistance(planetModel, distanceStyle, x,y,z);
+      if (distance != Double.MAX_VALUE)
+        return currentDistance + distance;
+      currentDistance += segment.fullPathDistance(distanceStyle);
+    }
+
+    int segmentIndex = 0;
+    currentDistance = 0.0;
+    for (SegmentEndpoint endpoint : endPoints) {
+      double distance = endpoint.pathDistance(distanceStyle, x, y, z);
+      if (distance != Double.MAX_VALUE)
+        return currentDistance + distance;
+      if (segmentIndex < segments.size())
+        currentDistance += segments.get(segmentIndex++).fullPathDistance(distanceStyle);
+    }
+
+    return Double.MAX_VALUE;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    double minDistance = Double.MAX_VALUE;
+    for (final SegmentEndpoint endpoint : endPoints) {
+      final double newDistance = endpoint.outsideDistance(distanceStyle, x,y,z);
+      if (newDistance < minDistance)
+        minDistance = newDistance;
+    }
+    for (final PathSegment segment : segments) {
+      final double newDistance = segment.outsideDistance(planetModel, distanceStyle, x, y, z);
+      if (newDistance < minDistance)
+        minDistance = newDistance;
+    }
+    return minDistance;
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    for (SegmentEndpoint pathPoint : endPoints) {
+      if (pathPoint.isWithin(x, y, z))
+        return true;
+    }
+    for (PathSegment pathSegment : segments) {
+      if (pathSegment.isWithin(x, y, z))
+        return true;
+    }
+    return false;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane plane, final GeoPoint[] notablePoints, final Membership... bounds) {
+    // We look for an intersection with any of the exterior edges of the path.
+    // We also have to look for intersections with the cones described by the endpoints.
+    // Return "true" if any such intersections are found.
+
+    // For plane intersections, the basic idea is to come up with an equation of the line that is
+    // the intersection (if any).  Then, find the intersections with the unit sphere (if any).  If
+    // any of the intersection points are within the bounds, then we've detected an intersection.
+    // Well, sort of.  We can detect intersections also due to overlap of segments with each other.
+    // But that's an edge case and we won't be optimizing for it.
+    //System.err.println(" Looking for intersection of plane "+plane+" with path "+this);
+    for (final SegmentEndpoint pathPoint : endPoints) {
+      if (pathPoint.intersects(planetModel, plane, notablePoints, bounds)) {
+        return true;
+      }
+    }
+
+    for (final PathSegment pathSegment : segments) {
+      if (pathSegment.intersects(planetModel, plane, notablePoints, bounds)) {
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    // For building bounds, order matters.  We want to traverse
+    // never more than 180 degrees longitude at a pop or we risk having the
+    // bounds object get itself inverted.  So do the edges first.
+    for (PathSegment pathSegment : segments) {
+      pathSegment.getBounds(planetModel, bounds);
+    }
+    for (SegmentEndpoint pathPoint : endPoints) {
+      pathPoint.getBounds(planetModel, bounds);
+    }
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoPath))
+      return false;
+    GeoPath p = (GeoPath) o;
+    if (!super.equals(p))
+      return false;
+    if (cutoffAngle != p.cutoffAngle)
+      return false;
+    return points.equals(p.points);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    long temp = Double.doubleToLongBits(cutoffAngle);
+    result = 31 * result + (int) (temp ^ (temp >>> 32));
+    result = 31 * result + points.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoPath: {planetmodel=" + planetModel+", width=" + cutoffAngle + "(" + cutoffAngle * 180.0 / Math.PI + "), points={" + points + "}}";
+  }
+
+  /**
+   * This is precalculated data for segment endpoint.
+   * Note well: This is not necessarily a circle.  There are four cases:
+   * (1) The path consists of a single endpoint.  In this case, we build a simple circle with the proper cutoff offset.
+   * (2) This is the end of a path.  The circle plane must be constructed to go through two supplied points and be perpendicular to a connecting plane.
+   * (2.5) Intersection, but the path on both sides is linear.  We generate a circle, but we use the cutoff planes to limit its influence in the straight line case.
+   * (3) This is an intersection in a path.  We are supplied FOUR planes.  If there are intersections within bounds for both upper and lower, then
+   *    we generate no circle at all.  If there is one intersection only, then we generate a plane that includes that intersection, as well as the remaining
+   *    cutoff plane/edge plane points.
+   */
+  public static class SegmentEndpoint {
+    /** The center point of the endpoint */
+    public final GeoPoint point;
+    /** A plane describing the circle */
+    public final SidedPlane circlePlane;
+    /** Pertinent cutoff planes from adjoining segments */
+    public final Membership[] cutoffPlanes;
+    /** Notable points for this segment endpoint */
+    public final GeoPoint[] notablePoints;
+    /** No notable points from the circle itself */
+    public final static GeoPoint[] circlePoints = new GeoPoint[0];
+    /** Null membership */
+    public final static Membership[] NO_MEMBERSHIP = new Membership[0];
+    
+    /** Base case.  Does nothing at all.
+     */
+    public SegmentEndpoint(final GeoPoint point) {
+      this.point = point;
+      this.circlePlane = null;
+      this.cutoffPlanes = null;
+      this.notablePoints = null;
+    }
+    
+    /** Constructor for case (1).
+     * Generate a simple circle cutoff plane.
+     *@param point is the center point.
+     *@param upperPoint is a point that must be on the circle plane.
+     *@param lowerPoint is another point that must be on the circle plane.
+     */
+    public SegmentEndpoint(final GeoPoint point, final Plane normalPlane, final GeoPoint upperPoint, final GeoPoint lowerPoint) {
+      this.point = point;
+      // Construct a sided plane that goes through the two points and whose normal is in the normalPlane.
+      this.circlePlane = SidedPlane.constructNormalizedPerpendicularSidedPlane(point, normalPlane, upperPoint, lowerPoint);
+      this.cutoffPlanes = NO_MEMBERSHIP;
+      this.notablePoints = circlePoints;
+    }
+    
+    /** Constructor for case (2).
+     * Generate an endpoint, given a single cutoff plane plus upper and lower edge points.
+     *@param point is the center point.
+     *@param cutoffPlane is the plane from the adjoining path segment marking the boundary between this endpoint and that segment.
+     *@param topEdgePoint is a point on the cutoffPlane that should be also on the circle plane.
+     *@param bottomEdgePoint is another point on the cutoffPlane that should be also on the circle plane.
+     */
+    public SegmentEndpoint(final GeoPoint point,
+      final SidedPlane cutoffPlane, final GeoPoint topEdgePoint, final GeoPoint bottomEdgePoint) {
+      this.point = point;
+      this.cutoffPlanes = new Membership[]{new SidedPlane(cutoffPlane)};
+      this.notablePoints = new GeoPoint[]{topEdgePoint, bottomEdgePoint};
+      // To construct the plane, we now just need D, which is simply the negative of the evaluation of the circle normal vector at one of the points.
+      this.circlePlane = SidedPlane.constructNormalizedPerpendicularSidedPlane(point, cutoffPlane, topEdgePoint, bottomEdgePoint);
+    }
+
+    /** Constructor for case (2.5).
+     * Generate an endpoint, given two cutoff planes plus upper and lower edge points.
+     *@param point is the center.
+     *@param cutoffPlane1 is one adjoining path segment cutoff plane.
+     *@param cutoffPlane2 is another adjoining path segment cutoff plane.
+     *@param topEdgePoint is a point on the cutoffPlane that should be also on the circle plane.
+     *@param bottomEdgePoint is another point on the cutoffPlane that should be also on the circle plane.
+     */
+    public SegmentEndpoint(final GeoPoint point,
+      final SidedPlane cutoffPlane1, final SidedPlane cutoffPlane2, final GeoPoint topEdgePoint, final GeoPoint bottomEdgePoint) {
+      this.point = point;
+      this.cutoffPlanes = new Membership[]{new SidedPlane(cutoffPlane1), new SidedPlane(cutoffPlane2)};
+      this.notablePoints = new GeoPoint[]{topEdgePoint, bottomEdgePoint};
+      // To construct the plane, we now just need D, which is simply the negative of the evaluation of the circle normal vector at one of the points.
+      this.circlePlane = SidedPlane.constructNormalizedPerpendicularSidedPlane(point, cutoffPlane1, topEdgePoint, bottomEdgePoint);
+    }
+    
+    /** Constructor for case (3).
+     * Generate an endpoint for an intersection, given four points.
+     *@param point is the center.
+     *@param prevCutoffPlane is the previous adjoining segment cutoff plane.
+     *@param nextCutoffPlane is the next path segment cutoff plane.
+     *@param notCand2Point is a point NOT on candidate2.
+     *@param notCand1Point is a point NOT on candidate1.
+     *@param notCand3Point is a point NOT on candidate3.
+     *@param notCand4Point is a point NOT on candidate4.
+     *@param candidate1 one of four candidate circle planes.
+     *@param candidate2 one of four candidate circle planes.
+     *@param candidate3 one of four candidate circle planes.
+     *@param candidate4 one of four candidate circle planes.
+     */
+    public SegmentEndpoint(final GeoPoint point,
+      final SidedPlane prevCutoffPlane, final SidedPlane nextCutoffPlane,
+      final GeoPoint notCand2Point, final GeoPoint notCand1Point,
+      final GeoPoint notCand3Point, final GeoPoint notCand4Point,
+      final SidedPlane candidate1, final SidedPlane candidate2, final SidedPlane candidate3, final SidedPlane candidate4) {
+      // Note: What we really need is a single plane that goes through all four points.
+      // Since that's not possible in the ellipsoid case (because three points determine a plane, not four), we
+      // need an approximation that at least creates a boundary that has no interruptions.
+      // There are three obvious choices for the third point: either (a) one of the two remaining points, or (b) the top or bottom edge
+      // intersection point.  (a) has no guarantee of continuity, while (b) is capable of producing something very far from a circle if
+      // the angle between segments is acute.
+      // The solution is to look for the side (top or bottom) that has an intersection within the shape.  We use the two points from
+      // the opposite side to determine the plane, AND we pick the third to be either of the two points on the intersecting side
+      // PROVIDED that the other point is within the final circle we come up with.
+      this.point = point;
+      
+      // We construct four separate planes, and evaluate which one includes all interior points with least overlap
+      // (Constructed beforehand because we need them for degeneracy check)
+
+      final boolean cand1IsOtherWithin = candidate1!=null?candidate1.isWithin(notCand1Point):false;
+      final boolean cand2IsOtherWithin = candidate2!=null?candidate2.isWithin(notCand2Point):false;
+      final boolean cand3IsOtherWithin = candidate3!=null?candidate3.isWithin(notCand3Point):false;
+      final boolean cand4IsOtherWithin = candidate4!=null?candidate4.isWithin(notCand4Point):false;
+      
+      if (cand1IsOtherWithin && cand2IsOtherWithin && cand3IsOtherWithin && cand4IsOtherWithin) {
+        // The only way we should see both within is if all four points are coplanar.  In that case, we default to the simplest treatment.
+        this.circlePlane = candidate1;  // doesn't matter which
+        this.notablePoints = new GeoPoint[]{notCand2Point, notCand3Point, notCand1Point, notCand4Point};
+        this.cutoffPlanes = new Membership[]{new SidedPlane(prevCutoffPlane), new SidedPlane(nextCutoffPlane)};
+      } else if (cand1IsOtherWithin) {
+        // Use candidate1, and DON'T include prevCutoffPlane in the cutoff planes list
+        this.circlePlane = candidate1;
+        this.notablePoints = new GeoPoint[]{notCand2Point, notCand3Point, notCand4Point};
+        this.cutoffPlanes = new Membership[]{new SidedPlane(nextCutoffPlane)};
+      } else if (cand2IsOtherWithin) {
+        // Use candidate2
+        this.circlePlane = candidate2;
+        this.notablePoints = new GeoPoint[]{notCand3Point, notCand4Point, notCand1Point};
+        this.cutoffPlanes = new Membership[]{new SidedPlane(nextCutoffPlane)};
+      } else if (cand3IsOtherWithin) {
+        this.circlePlane = candidate3;
+        this.notablePoints = new GeoPoint[]{notCand4Point, notCand1Point, notCand2Point};
+        this.cutoffPlanes = new Membership[]{new SidedPlane(prevCutoffPlane)};
+      } else if (cand4IsOtherWithin) {
+        this.circlePlane = candidate4;
+        this.notablePoints = new GeoPoint[]{notCand1Point, notCand2Point, notCand3Point};
+        this.cutoffPlanes = new Membership[]{new SidedPlane(prevCutoffPlane)};
+      } else {
+        // dunno what happened
+        throw new RuntimeException("Couldn't come up with a plane through three points that included the fourth");
+      }
+    }
+
+    /** Check if point is within this endpoint.
+     *@param point is the point.
+     *@return true of within.
+     */
+    public boolean isWithin(final Vector point) {
+      if (circlePlane == null)
+        return false;
+      if (!circlePlane.isWithin(point))
+        return false;
+      for (final Membership m : cutoffPlanes) {
+        if (!m.isWithin(point)) {
+          return false;
+        }
+      }
+      return true;
+    }
+
+    /** Check if point is within this endpoint.
+     *@param x is the point x.
+     *@param y is the point y.
+     *@param z is the point z.
+     *@return true of within.
+     */
+    public boolean isWithin(final double x, final double y, final double z) {
+      if (circlePlane == null)
+        return false;
+      if (!circlePlane.isWithin(x, y, z))
+        return false;
+      for (final Membership m : cutoffPlanes) {
+        if (!m.isWithin(x,y,z)) {
+          return false;
+        }
+      }
+      return true;
+    }
+
+    /** Compute interior path distance.
+     *@param distanceStyle is the distance style.
+     *@param x is the point x.
+     *@param y is the point y.
+     *@param z is the point z.
+     *@return the distance metric.
+     */
+    public double pathDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+      if (!isWithin(x,y,z))
+        return Double.MAX_VALUE;
+      return distanceStyle.computeDistance(this.point, x, y, z);
+    }
+
+    /** Compute external distance.
+     *@param distanceStyle is the distance style.
+     *@param x is the point x.
+     *@param y is the point y.
+     *@param z is the point z.
+     *@return the distance metric.
+     */
+    public double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+      return distanceStyle.computeDistance(this.point, x, y, z);
+    }
+
+    /** Determine if this endpoint intersects a specified plane.
+     *@param planetModel is the planet model.
+     *@param p is the plane.
+     *@param notablePoints are the points associated with the plane.
+     *@param bounds are any bounds which the intersection must lie within.
+     *@return true if there is a matching intersection.
+     */
+    public boolean intersects(final PlanetModel planetModel, final Plane p, final GeoPoint[] notablePoints, final Membership[] bounds) {
+      //System.err.println("  looking for intersection between plane "+p+" and circle "+circlePlane+" on proper side of "+cutoffPlanes+" within "+bounds);
+      if (circlePlane == null)
+        return false;
+      return circlePlane.intersects(planetModel, p, notablePoints, this.notablePoints, bounds, this.cutoffPlanes);
+    }
+
+    /** Get the bounds for a segment endpoint.
+     *@param planetModel is the planet model.
+     *@param bounds are the bounds to be modified.
+     */
+    public void getBounds(final PlanetModel planetModel, Bounds bounds) {
+      bounds.addPoint(point);
+      if (circlePlane == null)
+        return;
+      bounds.addPlane(planetModel, circlePlane);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      if (!(o instanceof SegmentEndpoint))
+        return false;
+      SegmentEndpoint other = (SegmentEndpoint) o;
+      return point.equals(other.point);
+    }
+
+    @Override
+    public int hashCode() {
+      return point.hashCode();
+    }
+
+    @Override
+    public String toString() {
+      return point.toString();
+    }
+  }
+
+  /**
+   * This is the pre-calculated data for a path segment.
+   */
+  public static class PathSegment {
+    /** Starting point of the segment */
+    public final GeoPoint start;
+    /** End point of the segment */
+    public final GeoPoint end;
+    /** Place to keep any complete segment distances we've calculated so far */
+    public final Map<DistanceStyle,Double> fullDistanceCache = new HashMap<DistanceStyle,Double>();
+    /** Normalized plane connecting the two points and going through world center */
+    public final Plane normalizedConnectingPlane;
+    /** Cutoff plane parallel to connecting plane representing one side of the path segment */
+    public final SidedPlane upperConnectingPlane;
+    /** Cutoff plane parallel to connecting plane representing the other side of the path segment */
+    public final SidedPlane lowerConnectingPlane;
+    /** Plane going through the center and start point, marking the start edge of the segment */
+    public final SidedPlane startCutoffPlane;
+    /** Plane going through the center and end point, marking the end edge of the segment */
+    public final SidedPlane endCutoffPlane;
+    /** Upper right hand corner of segment */
+    public final GeoPoint URHC;
+    /** Lower right hand corner of segment */
+    public final GeoPoint LRHC;
+    /** Upper left hand corner of segment */
+    public final GeoPoint ULHC;
+    /** Lower left hand corner of segment */
+    public final GeoPoint LLHC;
+    /** Notable points for the upper connecting plane */
+    public final GeoPoint[] upperConnectingPlanePoints;
+    /** Notable points for the lower connecting plane */
+    public final GeoPoint[] lowerConnectingPlanePoints;
+    /** Notable points for the start cutoff plane */
+    public final GeoPoint[] startCutoffPlanePoints;
+    /** Notable points for the end cutoff plane */
+    public final GeoPoint[] endCutoffPlanePoints;
+
+    /** Construct a path segment.
+     *@param planetModel is the planet model.
+     *@param start is the starting point.
+     *@param end is the ending point.
+     *@param normalizedConnectingPlane is the connecting plane.
+     *@param planeBoundingOffset is the linear offset from the connecting plane to either side.
+     */
+    public PathSegment(final PlanetModel planetModel, final GeoPoint start, final GeoPoint end,
+      final Plane normalizedConnectingPlane, final double planeBoundingOffset) {
+      this.start = start;
+      this.end = end;
+      this.normalizedConnectingPlane = normalizedConnectingPlane;
+        
+      // Either start or end should be on the correct side
+      upperConnectingPlane = new SidedPlane(start, normalizedConnectingPlane, -planeBoundingOffset);
+      lowerConnectingPlane = new SidedPlane(start, normalizedConnectingPlane, planeBoundingOffset);
+      // Cutoff planes use opposite endpoints as correct side examples
+      startCutoffPlane = new SidedPlane(end, normalizedConnectingPlane, start);
+      endCutoffPlane = new SidedPlane(start, normalizedConnectingPlane, end);
+      final Membership[] upperSide = new Membership[]{upperConnectingPlane};
+      final Membership[] lowerSide = new Membership[]{lowerConnectingPlane};
+      final Membership[] startSide = new Membership[]{startCutoffPlane};
+      final Membership[] endSide = new Membership[]{endCutoffPlane};
+      GeoPoint[] points;
+      points = upperConnectingPlane.findIntersections(planetModel, startCutoffPlane, lowerSide, endSide);
+      if (points.length == 0) {
+        throw new IllegalArgumentException("Some segment boundary points are off the ellipsoid; path too wide");
+      }
+      this.ULHC = points[0];
+      points = upperConnectingPlane.findIntersections(planetModel, endCutoffPlane, lowerSide, startSide);
+      if (points.length == 0) {
+        throw new IllegalArgumentException("Some segment boundary points are off the ellipsoid; path too wide");
+      }
+      this.URHC = points[0];
+      points = lowerConnectingPlane.findIntersections(planetModel, startCutoffPlane, upperSide, endSide);
+      if (points.length == 0) {
+        throw new IllegalArgumentException("Some segment boundary points are off the ellipsoid; path too wide");
+      }
+      this.LLHC = points[0];
+      points = lowerConnectingPlane.findIntersections(planetModel, endCutoffPlane, upperSide, startSide);
+      if (points.length == 0) {
+        throw new IllegalArgumentException("Some segment boundary points are off the ellipsoid; path too wide");
+      }
+      this.LRHC = points[0];
+      upperConnectingPlanePoints = new GeoPoint[]{ULHC, URHC};
+      lowerConnectingPlanePoints = new GeoPoint[]{LLHC, LRHC};
+      startCutoffPlanePoints = new GeoPoint[]{ULHC, LLHC};
+      endCutoffPlanePoints = new GeoPoint[]{URHC, LRHC};
+    }
+
+    /** Compute the full distance along this path segment.
+     *@param distanceStyle is the distance style.
+     *@return the distance metric.
+     */
+    public double fullPathDistance(final DistanceStyle distanceStyle) {
+      synchronized (fullDistanceCache) {
+        Double dist = fullDistanceCache.get(distanceStyle);
+        if (dist == null) {
+          dist = new Double(distanceStyle.computeDistance(start, end.x, end.y, end.z));
+          fullDistanceCache.put(distanceStyle, dist);
+        }
+        return dist.doubleValue();
+      }
+    }
+  
+    /** Check if point is within this segment.
+     *@param point is the point.
+     *@return true of within.
+     */
+    public boolean isWithin(final Vector point) {
+      return startCutoffPlane.isWithin(point) &&
+          endCutoffPlane.isWithin(point) &&
+          upperConnectingPlane.isWithin(point) &&
+          lowerConnectingPlane.isWithin(point);
+    }
+
+    /** Check if point is within this segment.
+     *@param x is the point x.
+     *@param y is the point y.
+     *@param z is the point z.
+     *@return true of within.
+     */
+    public boolean isWithin(final double x, final double y, final double z) {
+      return startCutoffPlane.isWithin(x, y, z) &&
+          endCutoffPlane.isWithin(x, y, z) &&
+          upperConnectingPlane.isWithin(x, y, z) &&
+          lowerConnectingPlane.isWithin(x, y, z);
+    }
+
+    /** Compute interior path distance.
+     *@param planetModel is the planet model.
+     *@param distanceStyle is the distance style.
+     *@param x is the point x.
+     *@param y is the point y.
+     *@param z is the point z.
+     *@return the distance metric.
+     */
+    public double pathDistance(final PlanetModel planetModel, final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+      if (!isWithin(x,y,z))
+        return Double.MAX_VALUE;
+
+      // (1) Compute normalizedPerpPlane.  If degenerate, then return point distance from start to point.
+      // Want no allocations or expensive operations!  so we do this the hard way
+      final double perpX = normalizedConnectingPlane.y * z - normalizedConnectingPlane.z * y;
+      final double perpY = normalizedConnectingPlane.z * x - normalizedConnectingPlane.x * z;
+      final double perpZ = normalizedConnectingPlane.x * y - normalizedConnectingPlane.y * x;
+      final double magnitude = Math.sqrt(perpX * perpX + perpY * perpY + perpZ * perpZ);
+      if (Math.abs(magnitude) < Vector.MINIMUM_RESOLUTION)
+        return distanceStyle.computeDistance(start, x,y,z);
+      final double normFactor = 1.0/magnitude;
+      final Plane normalizedPerpPlane = new Plane(perpX * normFactor, perpY * normFactor, perpZ * normFactor, 0.0);
+      
+      // Old computation: too expensive, because it calculates the intersection point twice.
+      //return distanceStyle.computeDistance(planetModel, normalizedConnectingPlane, x, y, z, startCutoffPlane, endCutoffPlane) +
+      //  distanceStyle.computeDistance(planetModel, normalizedPerpPlane, start.x, start.y, start.z, upperConnectingPlane, lowerConnectingPlane);
+
+      final GeoPoint[] intersectionPoints = normalizedConnectingPlane.findIntersections(planetModel, normalizedPerpPlane);
+      GeoPoint thePoint;
+      if (intersectionPoints.length == 0)
+        throw new RuntimeException("Can't find world intersection for point x="+x+" y="+y+" z="+z);
+      else if (intersectionPoints.length == 1)
+        thePoint = intersectionPoints[0];
+      else {
+        if (startCutoffPlane.isWithin(intersectionPoints[0]) && endCutoffPlane.isWithin(intersectionPoints[0]))
+          thePoint = intersectionPoints[0];
+        else if (startCutoffPlane.isWithin(intersectionPoints[1]) && endCutoffPlane.isWithin(intersectionPoints[1]))
+          thePoint = intersectionPoints[1];
+        else
+          throw new RuntimeException("Can't find world intersection for point x="+x+" y="+y+" z="+z);
+      }
+      return distanceStyle.computeDistance(thePoint, x, y, z) + distanceStyle.computeDistance(start, thePoint.x, thePoint.y, thePoint.z);
+    }
+
+    /** Compute external distance.
+     *@param planetModel is the planet model.
+     *@param distanceStyle is the distance style.
+     *@param x is the point x.
+     *@param y is the point y.
+     *@param z is the point z.
+     *@return the distance metric.
+     */
+    public double outsideDistance(final PlanetModel planetModel, final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+      final double upperDistance = distanceStyle.computeDistance(planetModel, upperConnectingPlane, x,y,z, lowerConnectingPlane, startCutoffPlane, endCutoffPlane);
+      final double lowerDistance = distanceStyle.computeDistance(planetModel, lowerConnectingPlane, x,y,z, upperConnectingPlane, startCutoffPlane, endCutoffPlane);
+      final double startDistance = distanceStyle.computeDistance(planetModel, startCutoffPlane, x,y,z, endCutoffPlane, lowerConnectingPlane, upperConnectingPlane);
+      final double endDistance = distanceStyle.computeDistance(planetModel, endCutoffPlane, x,y,z, startCutoffPlane, lowerConnectingPlane, upperConnectingPlane);
+      final double ULHCDistance = distanceStyle.computeDistance(ULHC, x,y,z);
+      final double URHCDistance = distanceStyle.computeDistance(URHC, x,y,z);
+      final double LLHCDistance = distanceStyle.computeDistance(LLHC, x,y,z);
+      final double LRHCDistance = distanceStyle.computeDistance(LRHC, x,y,z);
+      return Math.min(
+        Math.min(
+          Math.min(upperDistance,lowerDistance),
+          Math.min(startDistance,endDistance)),
+        Math.min(
+          Math.min(ULHCDistance, URHCDistance),
+          Math.min(LLHCDistance, LRHCDistance)));
+    }
+
+    /** Determine if this endpoint intersects a specified plane.
+     *@param planetModel is the planet model.
+     *@param p is the plane.
+     *@param notablePoints are the points associated with the plane.
+     *@param bounds are any bounds which the intersection must lie within.
+     *@return true if there is a matching intersection.
+     */
+    public boolean intersects(final PlanetModel planetModel, final Plane p, final GeoPoint[] notablePoints, final Membership[] bounds) {
+      return upperConnectingPlane.intersects(planetModel, p, notablePoints, upperConnectingPlanePoints, bounds, lowerConnectingPlane, startCutoffPlane, endCutoffPlane) ||
+          lowerConnectingPlane.intersects(planetModel, p, notablePoints, lowerConnectingPlanePoints, bounds, upperConnectingPlane, startCutoffPlane, endCutoffPlane);
+    }
+
+    /** Get the bounds for a segment endpoint.
+     *@param planetModel is the planet model.
+     *@param bounds are the bounds to be modified.
+     */
+    public void getBounds(final PlanetModel planetModel, Bounds bounds) {
+      // We need to do all bounding planes as well as corner points
+      bounds.addPoint(start).addPoint(end).addPoint(ULHC).addPoint(URHC).addPoint(LRHC).addPoint(LLHC);
+      bounds.addPlane(planetModel, upperConnectingPlane, lowerConnectingPlane, startCutoffPlane, endCutoffPlane);
+      bounds.addPlane(planetModel, lowerConnectingPlane, upperConnectingPlane, startCutoffPlane, endCutoffPlane);
+      bounds.addPlane(planetModel, startCutoffPlane, endCutoffPlane, upperConnectingPlane, lowerConnectingPlane);
+      bounds.addPlane(planetModel, endCutoffPlane, startCutoffPlane, upperConnectingPlane, lowerConnectingPlane);
+    }
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPoint.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPoint.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPoint.java
new file mode 100755
index 0000000..31ab0aa
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPoint.java
@@ -0,0 +1,193 @@
+/*
+ * 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.spatial3d.geom;
+    
+/**
+ * This class represents a point on the surface of a sphere or ellipsoid.
+ *
+ * @lucene.experimental
+ */
+public class GeoPoint extends Vector {
+  
+  // By making lazily-evaluated variables be "volatile", we guarantee atomicity when they
+  // are updated.  This is necessary if we are using these classes in a multi-thread fashion,
+  // because we don't try to synchronize for the lazy computation.
+  
+  /** This is the lazily-evaluated magnitude.  Some constructors include it, but others don't, and
+   * we try not to create extra computation by always computing it.  Does not need to be
+   * synchronized for thread safety, because depends wholly on immutable variables of this class. */
+  protected volatile double magnitude = Double.NEGATIVE_INFINITY;
+  /** Lazily-evaluated latitude.  Does not need to be
+   * synchronized for thread safety, because depends wholly on immutable variables of this class.  */
+  protected volatile double latitude = Double.NEGATIVE_INFINITY;
+  /** Lazily-evaluated longitude.   Does not need to be
+   * synchronized for thread safety, because depends wholly on immutable variables of this class.  */
+  protected volatile double longitude = Double.NEGATIVE_INFINITY;
+
+  /** Construct a GeoPoint from the trig functions of a lat and lon pair.
+   * @param planetModel is the planetModel to put the point on.
+   * @param sinLat is the sin of the latitude.
+   * @param sinLon is the sin of the longitude.
+   * @param cosLat is the cos of the latitude.
+   * @param cosLon is the cos of the longitude.
+   * @param lat is the latitude.
+   * @param lon is the longitude.
+   */
+  public GeoPoint(final PlanetModel planetModel, final double sinLat, final double sinLon, final double cosLat, final double cosLon, final double lat, final double lon) {
+    this(computeDesiredEllipsoidMagnitude(planetModel, cosLat * cosLon, cosLat * sinLon, sinLat),
+      cosLat * cosLon, cosLat * sinLon, sinLat, lat, lon);
+  }
+  
+  /** Construct a GeoPoint from the trig functions of a lat and lon pair.
+   * @param planetModel is the planetModel to put the point on.
+   * @param sinLat is the sin of the latitude.
+   * @param sinLon is the sin of the longitude.
+   * @param cosLat is the cos of the latitude.
+   * @param cosLon is the cos of the longitude.
+   */
+  public GeoPoint(final PlanetModel planetModel, final double sinLat, final double sinLon, final double cosLat, final double cosLon) {
+    this(computeDesiredEllipsoidMagnitude(planetModel, cosLat * cosLon, cosLat * sinLon, sinLat),
+      cosLat * cosLon, cosLat * sinLon, sinLat);
+  }
+
+  /** Construct a GeoPoint from a latitude/longitude pair.
+   * @param planetModel is the planetModel to put the point on.
+   * @param lat is the latitude.
+   * @param lon is the longitude.
+   */
+  public GeoPoint(final PlanetModel planetModel, final double lat, final double lon) {
+    this(planetModel, Math.sin(lat), Math.sin(lon), Math.cos(lat), Math.cos(lon), lat, lon);
+  }
+  
+  /** Construct a GeoPoint from a unit (x,y,z) vector and a magnitude.
+   * @param magnitude is the desired magnitude, provided to put the point on the ellipsoid.
+   * @param x is the unit x value.
+   * @param y is the unit y value.
+   * @param z is the unit z value.
+   * @param lat is the latitude.
+   * @param lon is the longitude.
+   */
+  public GeoPoint(final double magnitude, final double x, final double y, final double z, double lat, double lon) {
+    super(x * magnitude, y * magnitude, z * magnitude);
+    this.magnitude = magnitude;
+    if (lat > Math.PI * 0.5 || lat < -Math.PI * 0.5) {
+      throw new IllegalArgumentException("Latitude " + lat + " is out of range: must range from -Math.PI/2 to Math.PI/2");
+    }
+    if (lon < -Math.PI || lon > Math.PI) {
+      throw new IllegalArgumentException("Longitude " + lon + " is out of range: must range from -Math.PI to Math.PI");
+    }
+    this.latitude = lat;
+    this.longitude = lon;
+  }
+
+  /** Construct a GeoPoint from a unit (x,y,z) vector and a magnitude.
+   * @param magnitude is the desired magnitude, provided to put the point on the ellipsoid.
+   * @param x is the unit x value.
+   * @param y is the unit y value.
+   * @param z is the unit z value.
+   */
+  public GeoPoint(final double magnitude, final double x, final double y, final double z) {
+    super(x * magnitude, y * magnitude, z * magnitude);
+    this.magnitude = magnitude;
+  }
+  
+  /** Construct a GeoPoint from an (x,y,z) value.
+   * The (x,y,z) tuple must be on the desired ellipsoid.
+   * @param x is the ellipsoid point x value.
+   * @param y is the ellipsoid point y value.
+   * @param z is the ellipsoid point z value.
+   */
+  public GeoPoint(final double x, final double y, final double z) {
+    super(x, y, z);
+  }
+
+  /** Compute an arc distance between two points.
+   * Note: this is an angular distance, and not a surface distance, and is therefore independent of planet model.
+   * For surface distance, see {@link PlanetModel#surfaceDistance(GeoPoint, GeoPoint)}
+   * @param v is the second point.
+   * @return the angle, in radians, between the two points.
+   */
+  public double arcDistance(final GeoPoint v) {
+    return Tools.safeAcos(dotProduct(v)/(magnitude() * v.magnitude()));
+  }
+
+  /** Compute an arc distance between two points.
+   * @param x is the x part of the second point.
+   * @param y is the y part of the second point.
+   * @param z is the z part of the second point.
+   * @return the angle, in radians, between the two points.
+   */
+  public double arcDistance(final double x, final double y, final double z) {
+    return Tools.safeAcos(dotProduct(x,y,z)/(magnitude() * Vector.magnitude(x,y,z)));
+  }
+
+  /** Compute the latitude for the point.
+   * @return the latitude.
+   */
+  public double getLatitude() {
+    double lat = this.latitude;//volatile-read once
+    if (lat == Double.NEGATIVE_INFINITY)
+      this.latitude = lat = Math.asin(z / magnitude());
+    return lat;
+  }
+  
+  /** Compute the longitude for the point.
+   * @return the longitude value.  Uses 0.0 if there is no computable longitude.
+   */
+  public double getLongitude() {
+    double lon = this.longitude;//volatile-read once
+    if (lon == Double.NEGATIVE_INFINITY) {
+      if (Math.abs(x) < MINIMUM_RESOLUTION && Math.abs(y) < MINIMUM_RESOLUTION)
+        this.longitude = lon = 0.0;
+      else
+        this.longitude = lon = Math.atan2(y,x);
+    }
+    return lon;
+  }
+  
+  /** Compute the linear magnitude of the point.
+   * @return the magnitude.
+   */
+  @Override
+  public double magnitude() {
+    double mag = this.magnitude;//volatile-read once
+    if (mag == Double.NEGATIVE_INFINITY) {
+      this.magnitude = mag = super.magnitude();
+    }
+    return mag;
+  }
+  
+  /** Compute whether point matches another.
+   *@param x is the x value
+   *@param y is the y value
+   *@param z is the z value
+   *@return true if the same.
+   */
+  public boolean isIdentical(final double x, final double y, final double z) {
+    return Math.abs(this.x - x) < MINIMUM_RESOLUTION &&
+      Math.abs(this.y - y) < MINIMUM_RESOLUTION &&
+      Math.abs(this.z - z) < MINIMUM_RESOLUTION;
+  }
+  
+  @Override
+  public String toString() {
+    if (this.longitude == Double.NEGATIVE_INFINITY) {
+      return super.toString();
+    }
+    return "[lat="+getLatitude()+", lon="+getLongitude()+"]";
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygon.java
new file mode 100644
index 0000000..742bdf8
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygon.java
@@ -0,0 +1,26 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * GeoPolygon interface description.
+ *
+ * @lucene.experimental
+ */
+public interface GeoPolygon extends GeoMembershipShape {
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java
new file mode 100755
index 0000000..8ee4290
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java
@@ -0,0 +1,187 @@
+/*
+ * 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.spatial3d.geom;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.List;
+
+/**
+ * Class which constructs a GeoMembershipShape representing an arbitrary polygon.
+ *
+ * @lucene.experimental
+ */
+public class GeoPolygonFactory {
+  private GeoPolygonFactory() {
+  }
+
+  /**
+   * Create a GeoMembershipShape of the right kind given the specified bounds.
+   *
+   * @param pointList        is a list of the GeoPoints to build an arbitrary polygon out of.
+   * @param convexPointIndex is the index of a single convex point whose conformation with
+   *                         its neighbors determines inside/outside for the entire polygon.
+   * @return a GeoPolygon corresponding to what was specified.
+   */
+  public static GeoPolygon makeGeoPolygon(final PlanetModel planetModel, final List<GeoPoint> pointList, final int convexPointIndex) {
+    // The basic operation uses a set of points, two points determining one particular edge, and a sided plane
+    // describing membership.
+    return buildPolygonShape(planetModel, pointList, convexPointIndex, getLegalIndex(convexPointIndex + 1, pointList.size()),
+        new SidedPlane(pointList.get(getLegalIndex(convexPointIndex - 1, pointList.size())),
+            pointList.get(convexPointIndex), pointList.get(getLegalIndex(convexPointIndex + 1, pointList.size()))),
+        false);
+  }
+
+  /** Build a GeoMembershipShape given points, starting edge, and whether starting edge is internal or not.
+   * @param pointsList        is a list of the GeoPoints to build an arbitrary polygon out of.
+   * @param startPointIndex is one of the points constituting the starting edge.
+   * @param endPointIndex is another of the points constituting the starting edge.
+   * @param startingEdge is the plane describing the starting edge.
+   * @param isInternalEdge is true if the specified edge is an internal one.
+   * @return a GeoMembershipShape corresponding to what was specified.
+   */
+  public static GeoPolygon buildPolygonShape(final PlanetModel planetModel, final List<GeoPoint> pointsList, final int startPointIndex, final int endPointIndex, final SidedPlane startingEdge, final boolean isInternalEdge) {
+    // Algorithm as follows:
+    // Start with sided edge.  Go through all points in some order.  For each new point, determine if the point is within all edges considered so far.
+    // If not, put it into a list of points for recursion.  If it is within, add new edge and keep going.
+    // Once we detect a point that is within, if there are points put aside for recursion, then call recursively.
+
+    // Current composite.  This is what we'll actually be returning.
+    final GeoCompositePolygon rval = new GeoCompositePolygon();
+
+    final List<GeoPoint> recursionList = new ArrayList<GeoPoint>();
+    final List<GeoPoint> currentList = new ArrayList<GeoPoint>();
+    final BitSet internalEdgeList = new BitSet();
+    final List<SidedPlane> currentPlanes = new ArrayList<SidedPlane>();
+
+    // Initialize the current list and current planes
+    currentList.add(pointsList.get(startPointIndex));
+    currentList.add(pointsList.get(endPointIndex));
+    internalEdgeList.set(currentPlanes.size(), isInternalEdge);
+    currentPlanes.add(startingEdge);
+
+    // Now, scan all remaining points, in order.  We'll use an index and just add to it.
+    for (int i = 0; i < pointsList.size() - 2; i++) {
+      GeoPoint newPoint = pointsList.get(getLegalIndex(i + endPointIndex + 1, pointsList.size()));
+      if (isWithin(newPoint, currentPlanes)) {
+        // Construct a sided plane based on the last two points, and the previous point
+        SidedPlane newBoundary = new SidedPlane(currentList.get(currentList.size() - 2), newPoint, currentList.get(currentList.size() - 1));
+        // Construct a sided plane based on the return trip
+        SidedPlane returnBoundary = new SidedPlane(currentList.get(currentList.size() - 1), currentList.get(0), newPoint);
+        // Verify that none of the points beyond the new point in the list are inside the polygon we'd
+        // be creating if we stopped making the current polygon right now.
+        boolean pointInside = false;
+        for (int j = i + 1; j < pointsList.size() - 2; j++) {
+          GeoPoint checkPoint = pointsList.get(getLegalIndex(j + endPointIndex + 1, pointsList.size()));
+          boolean isInside = true;
+          if (isInside && !newBoundary.isWithin(checkPoint))
+            isInside = false;
+          if (isInside && !returnBoundary.isWithin(checkPoint))
+            isInside = false;
+          if (isInside) {
+            for (SidedPlane plane : currentPlanes) {
+              if (!plane.isWithin(checkPoint)) {
+                isInside = false;
+                break;
+              }
+            }
+          }
+          if (isInside) {
+            pointInside = true;
+            break;
+          }
+        }
+        if (!pointInside) {
+          // Any excluded points?
+          boolean isInternalBoundary = recursionList.size() > 0;
+          if (isInternalBoundary) {
+            // Handle exclusion
+            recursionList.add(newPoint);
+            recursionList.add(currentList.get(currentList.size() - 1));
+            if (recursionList.size() == pointsList.size()) {
+              // We are trying to recurse with a list the same size as the one we started with.
+              // Clearly, the polygon cannot be constructed
+              throw new IllegalArgumentException("Polygon is illegal; cannot be decomposed into convex parts");
+            }
+            // We want the other side for the recursion
+            SidedPlane otherSideNewBoundary = new SidedPlane(newBoundary);
+            rval.addShape(buildPolygonShape(planetModel, recursionList, recursionList.size() - 2, recursionList.size() - 1, otherSideNewBoundary, true));
+            recursionList.clear();
+          }
+          currentList.add(newPoint);
+          internalEdgeList.set(currentPlanes.size(), isInternalBoundary);
+          currentPlanes.add(newBoundary);
+        } else {
+          recursionList.add(newPoint);
+        }
+      } else {
+        recursionList.add(newPoint);
+      }
+    }
+
+    boolean returnEdgeInternalBoundary = recursionList.size() > 0;
+    if (returnEdgeInternalBoundary) {
+      // The last step back to the start point had a recursion, so take care of that before we complete our work
+      recursionList.add(currentList.get(0));
+      recursionList.add(currentList.get(currentList.size() - 1));
+      if (recursionList.size() == pointsList.size()) {
+        // We are trying to recurse with a list the same size as the one we started with.
+        // Clearly, the polygon cannot be constructed
+        throw new IllegalArgumentException("Polygon is illegal; cannot be decomposed into convex parts");
+      }
+      // Construct a sided plane based on these two points, and the previous point
+      SidedPlane newBoundary = new SidedPlane(currentList.get(currentList.size() - 2), currentList.get(0), currentList.get(currentList.size() - 1));
+      // We want the other side for the recursion
+      SidedPlane otherSideNewBoundary = new SidedPlane(newBoundary);
+      rval.addShape(buildPolygonShape(planetModel, recursionList, recursionList.size() - 2, recursionList.size() - 1, otherSideNewBoundary, true));
+      recursionList.clear();
+    }
+    // Now, add in the current shape.
+    rval.addShape(new GeoConvexPolygon(planetModel, currentList, internalEdgeList, returnEdgeInternalBoundary));
+    //System.out.println("Done creating polygon");
+    return rval;
+  }
+
+  /** Check if a point is within a described list of planes.
+   *@param newPoint is the point. 
+   *@param currentPlanes is the list of planes.
+   *@return true if within.
+   */
+  protected static boolean isWithin(final GeoPoint newPoint, final List<SidedPlane> currentPlanes) {
+    for (SidedPlane p : currentPlanes) {
+      if (!p.isWithin(newPoint))
+        return false;
+    }
+    return true;
+  }
+
+  /** Convert raw point index into valid array position.
+   *@param index is the array index.
+   *@param size is the array size.
+   *@return an updated index.
+   */
+  protected static int getLegalIndex(int index, int size) {
+    while (index < 0) {
+      index += size;
+    }
+    while (index >= size) {
+      index -= size;
+    }
+    return index;
+  }
+
+}


[17/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 3a31a8c)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoBBoxTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoBBoxTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoBBoxTest.java
new file mode 100755
index 0000000..f5a148f
--- /dev/null
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoBBoxTest.java
@@ -0,0 +1,364 @@
+/*
+ * 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.spatial3d.geom;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class GeoBBoxTest {
+
+  protected final double DEGREES_TO_RADIANS = Math.PI / 180.0;
+
+  @Test
+  public void testBBoxDegenerate() {
+    GeoBBox box;
+    GeoConvexPolygon cp;
+    int relationship;
+    List<GeoPoint> points = new ArrayList<GeoPoint>();
+    points.add(new GeoPoint(PlanetModel.SPHERE, 24 * DEGREES_TO_RADIANS, -30 * DEGREES_TO_RADIANS));
+    points.add(new GeoPoint(PlanetModel.SPHERE, -11 * DEGREES_TO_RADIANS, 101 * DEGREES_TO_RADIANS));
+    points.add(new GeoPoint(PlanetModel.SPHERE, -49 * DEGREES_TO_RADIANS, -176 * DEGREES_TO_RADIANS));
+    GeoMembershipShape shape = GeoPolygonFactory.makeGeoPolygon(PlanetModel.SPHERE, points, 0);
+    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, -64 * DEGREES_TO_RADIANS, -64 * DEGREES_TO_RADIANS, -180 * DEGREES_TO_RADIANS, 180 * DEGREES_TO_RADIANS);
+    relationship = box.getRelationship(shape);
+    assertEquals(GeoArea.CONTAINS, relationship);
+    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, -61.85 * DEGREES_TO_RADIANS, -67.5 * DEGREES_TO_RADIANS, -180 * DEGREES_TO_RADIANS, -168.75 * DEGREES_TO_RADIANS);
+    //System.out.println("Shape = " + shape + " Rect = " + box);
+    relationship = box.getRelationship(shape);
+    assertEquals(GeoArea.CONTAINS, relationship);
+  }
+
+  @Test
+  public void testBBoxPointWithin() {
+    GeoBBox box;
+    GeoPoint gp;
+
+    // Standard normal Rect box, not crossing dateline
+    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, -1.0, 1.0);
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, 0.0);
+    assertTrue(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.1, 0.0);
+    assertFalse(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0);
+    assertFalse(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, 1.1);
+    assertFalse(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -1.1);
+    assertFalse(box.isWithin(gp));
+    assertEquals(0.1,box.computeOutsideDistance(DistanceStyle.ARC,gp),1e-2);
+    assertEquals(0.1,box.computeOutsideDistance(DistanceStyle.NORMAL,gp),1e-2);
+    assertEquals(0.1,box.computeOutsideDistance(DistanceStyle.NORMAL,gp),1e-2);
+
+    // Standard normal Rect box, crossing dateline
+    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, Math.PI - 1.0, -Math.PI + 1.0);
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -Math.PI);
+    assertTrue(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.1, -Math.PI);
+    assertFalse(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.5, -Math.PI);
+    assertFalse(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -Math.PI + 1.1);
+    assertFalse(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, (-Math.PI - 1.1) + Math.PI * 2.0);
+    assertFalse(box.isWithin(gp));
+
+    // Latitude zone rectangle
+    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, -Math.PI, Math.PI);
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -Math.PI);
+    assertTrue(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.1, -Math.PI);
+    assertFalse(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.5, -Math.PI);
+    assertFalse(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -Math.PI + 1.1);
+    assertTrue(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, (-Math.PI - 1.1) + Math.PI * 2.0);
+    assertTrue(box.isWithin(gp));
+
+    // World
+    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, -Math.PI, Math.PI);
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -Math.PI);
+    assertTrue(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.1, -Math.PI);
+    assertTrue(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.5, -Math.PI);
+    assertTrue(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -Math.PI + 1.1);
+    assertTrue(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, (-Math.PI - 1.1) + Math.PI * 2.0);
+    assertTrue(box.isWithin(gp));
+
+  }
+
+  @Test
+  public void testBBoxExpand() {
+    GeoBBox box;
+    GeoPoint gp;
+    // Standard normal Rect box, not crossing dateline
+    box = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, -1.0, 1.0);
+    box = box.expand(0.1);
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, 0.0);
+    assertTrue(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.15, 0.0);
+    assertFalse(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.25 - 0.05, 0.0);
+    assertTrue(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.25 - 0.15, 0.0);
+    assertFalse(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -1.05);
+    assertTrue(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -1.15);
+    assertFalse(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, 1.05);
+    assertTrue(box.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, 1.15);
+    assertFalse(box.isWithin(gp));
+  }
+
+  @Test
+  public void testBBoxBounds() {
+    GeoBBox c;
+    LatLonBounds b;
+    XYZBounds xyzb;
+    GeoArea solid;
+    GeoPoint point;
+    int relationship;
+    
+    c= GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.7570958596622309, -0.7458670829264561, -0.9566079379002148, 1.4802570961901191);
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE,0.10922258701604912,0.1248184603754517,-0.8172414690802067,0.9959041483215542,-0.6136586624726926,0.6821740363641521);
+    point = new GeoPoint(PlanetModel.SPHERE, 0.3719987557178081, 1.4529582778845198);
+    assertTrue(c.isWithin(point));
+    assertTrue(solid.isWithin(point));
+    relationship = solid.getRelationship(c);
+    assertTrue(relationship == GeoArea.OVERLAPS || relationship == GeoArea.CONTAINS || relationship == GeoArea.WITHIN);
+
+    c= GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.006607096847842122, -0.002828135860810422, -0.0012934461873348349, 0.006727418645092394);
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE,0.9999995988328008,1.0000000002328306,-0.0012934708508166816,0.006727393021214471,-0.002828157275369464,0.006607074060760007);
+    point = new GeoPoint(PlanetModel.SPHERE, -5.236470872437899E-4, 3.992578692654256E-4);
+    assertTrue(c.isWithin(point));
+    assertTrue(solid.isWithin(point));
+    relationship = solid.getRelationship(c);
+    assertTrue(relationship == GeoArea.OVERLAPS || relationship == GeoArea.CONTAINS || relationship == GeoArea.WITHIN);
+    
+    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.25, -Math.PI * 0.25, -1.0, 1.0);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(-1.0, b.getLeftLongitude(), 0.000001);
+    assertEquals(1.0, b.getRightLongitude(), 0.000001);
+    assertEquals(-Math.PI * 0.25, b.getMinLatitude(), 0.000001);
+    assertEquals(Math.PI * 0.25, b.getMaxLatitude(), 0.000001);
+    assertEquals(0.382051, xyzb.getMinimumX(), 0.000001);
+    assertEquals(1.0, xyzb.getMaximumX(), 0.000001);
+    assertEquals(-0.841471, xyzb.getMinimumY(), 0.000001);
+    assertEquals(0.841471, xyzb.getMaximumY(), 0.000001);
+    assertEquals(-0.707107, xyzb.getMinimumZ(), 0.000001);
+    assertEquals(0.707107, xyzb.getMaximumZ(), 0.000001);
+    
+    GeoArea area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE,
+      xyzb.getMinimumX() - 2.0 * Vector.MINIMUM_RESOLUTION,
+      xyzb.getMaximumX() + 2.0 * Vector.MINIMUM_RESOLUTION,
+      xyzb.getMinimumY() - 2.0 * Vector.MINIMUM_RESOLUTION,
+      xyzb.getMaximumY() + 2.0 * Vector.MINIMUM_RESOLUTION,
+      xyzb.getMinimumZ() - 2.0 * Vector.MINIMUM_RESOLUTION,
+      xyzb.getMaximumZ() + 2.0 * Vector.MINIMUM_RESOLUTION);
+    assertEquals(GeoArea.WITHIN, area.getRelationship(c));
+
+    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, -1.0, 1.0);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(-1.0, b.getLeftLongitude(), 0.000001);
+    assertEquals(1.0, b.getRightLongitude(), 0.000001);
+    assertEquals(-Math.PI * 0.25, b.getMinLatitude(), 0.000001);
+    assertEquals(0.0, b.getMaxLatitude(), 0.000001);
+    assertEquals(0.382051, xyzb.getMinimumX(), 0.000001);
+    assertEquals(1.0, xyzb.getMaximumX(), 0.000001);
+    assertEquals(-0.841471, xyzb.getMinimumY(), 0.000001);
+    assertEquals(0.841471, xyzb.getMaximumY(), 0.000001);
+    assertEquals(-0.707107, xyzb.getMinimumZ(), 0.000001);
+    assertEquals(0.0, xyzb.getMaximumZ(), 0.000001);
+
+    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, 1.0, -1.0);
+
+    b = new LatLonBounds();
+    c.getBounds(b);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    assertTrue(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    //assertEquals(1.0,b.getLeftLongitude(),0.000001);
+    //assertEquals(-1.0,b.getRightLongitude(),0.000001);
+    assertEquals(-Math.PI * 0.25, b.getMinLatitude(), 0.000001);
+    assertEquals(0.0, b.getMaxLatitude(), 0.000001);
+    assertEquals(-1.0, xyzb.getMinimumX(), 0.000001);
+    assertEquals(0.540303, xyzb.getMaximumX(), 0.000001);
+    assertEquals(-1.0, xyzb.getMinimumY(), 0.000001);
+    assertEquals(1.0, xyzb.getMaximumY(), 0.000001);
+    assertEquals(-0.707107, xyzb.getMinimumZ(), 0.000001);
+    assertEquals(0.0, xyzb.getMaximumZ(), 0.000001);
+
+
+    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, -1.0, 1.0);
+
+    b = new LatLonBounds();
+    c.getBounds(b);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    assertTrue(b.checkNoLongitudeBound());
+    assertTrue(b.checkNoTopLatitudeBound());
+    assertTrue(b.checkNoBottomLatitudeBound());
+    //assertEquals(-1.0, b.getLeftLongitude(), 0.000001);
+    //assertEquals(1.0, b.getRightLongitude(), 0.000001);
+    assertEquals(0.0, xyzb.getMinimumX(), 0.000001);
+    assertEquals(1.0, xyzb.getMaximumX(), 0.000001);
+    assertEquals(-0.841471, xyzb.getMinimumY(), 0.000001);
+    assertEquals(0.841471, xyzb.getMaximumY(), 0.000001);
+    assertEquals(-1.0, xyzb.getMinimumZ(), 0.000001);
+    assertEquals(1.0, xyzb.getMaximumZ(), 0.000001);
+
+    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, 1.0, -1.0);
+
+    b = new LatLonBounds();
+    c.getBounds(b);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    assertTrue(b.checkNoLongitudeBound());
+    assertTrue(b.checkNoTopLatitudeBound());
+    assertTrue(b.checkNoBottomLatitudeBound());
+    //assertEquals(1.0,b.getLeftLongitude(),0.000001);
+    //assertEquals(-1.0,b.getRightLongitude(),0.000001);
+    assertEquals(-1.0, xyzb.getMinimumX(), 0.000001);
+    assertEquals(0.540303, xyzb.getMaximumX(), 0.000001);
+    assertEquals(-1.0, xyzb.getMinimumY(), 0.000001);
+    assertEquals(1.0, xyzb.getMaximumY(), 0.000001);
+    assertEquals(-1.0, xyzb.getMinimumZ(), 0.000001);
+    assertEquals(1.0, xyzb.getMaximumZ(), 0.000001);
+
+    // Check wide variants of rectangle and longitude slice
+
+    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, -Math.PI + 0.1, Math.PI - 0.1);
+
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertTrue(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    //assertEquals(-Math.PI+0.1,b.getLeftLongitude(),0.000001);
+    //assertEquals(Math.PI-0.1,b.getRightLongitude(),0.000001);
+    assertEquals(-Math.PI * 0.25, b.getMinLatitude(), 0.000001);
+    assertEquals(0.0, b.getMaxLatitude(), 0.000001);
+
+    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 0.0, -Math.PI * 0.25, Math.PI - 0.1, -Math.PI + 0.1);
+
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(Math.PI - 0.1, b.getLeftLongitude(), 0.000001);
+    assertEquals(-Math.PI + 0.1, b.getRightLongitude(), 0.000001);
+    assertEquals(-Math.PI * 0.25, b.getMinLatitude(), 0.000001);
+    assertEquals(0.0, b.getMaxLatitude(), 0.000001);
+
+    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, -Math.PI + 0.1, Math.PI - 0.1);
+
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertTrue(b.checkNoLongitudeBound());
+    assertTrue(b.checkNoTopLatitudeBound());
+    assertTrue(b.checkNoBottomLatitudeBound());
+    //assertEquals(-Math.PI+0.1,b.getLeftLongitude(),0.000001);
+    //assertEquals(Math.PI-0.1,b.getRightLongitude(),0.000001);
+
+    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, Math.PI - 0.1, -Math.PI + 0.1);
+
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertTrue(b.checkNoLongitudeBound());
+    assertTrue(b.checkNoTopLatitudeBound());
+    assertTrue(b.checkNoBottomLatitudeBound());
+    //assertEquals(Math.PI - 0.1, b.getLeftLongitude(), 0.000001);
+    //assertEquals(-Math.PI + 0.1, b.getRightLongitude(), 0.000001);
+
+    // Check latitude zone
+    c = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, 1.0, -1.0, -Math.PI, Math.PI);
+
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertTrue(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(-1.0, b.getMinLatitude(), 0.000001);
+    assertEquals(1.0, b.getMaxLatitude(), 0.000001);
+
+    // Now, combine a few things to test the bounds object
+    GeoBBox c1;
+    GeoBBox c2;
+
+    c1 = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, -Math.PI, 0.0);
+    c2 = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, 0.0, Math.PI);
+
+    b = new LatLonBounds();
+    c1.getBounds(b);
+    c2.getBounds(b);
+    assertTrue(b.checkNoLongitudeBound());
+    assertTrue(b.checkNoTopLatitudeBound());
+    assertTrue(b.checkNoBottomLatitudeBound());
+
+    c1 = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, -Math.PI, 0.0);
+    c2 = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, 0.0, Math.PI * 0.5);
+
+    b = new LatLonBounds();
+    c1.getBounds(b);
+    c2.getBounds(b);
+    assertTrue(b.checkNoLongitudeBound());
+    assertTrue(b.checkNoTopLatitudeBound());
+    assertTrue(b.checkNoBottomLatitudeBound());
+    //assertEquals(-Math.PI,b.getLeftLongitude(),0.000001);
+    //assertEquals(Math.PI*0.5,b.getRightLongitude(),0.000001);
+
+    c1 = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, -Math.PI * 0.5, 0.0);
+    c2 = GeoBBoxFactory.makeGeoBBox(PlanetModel.SPHERE, Math.PI * 0.5, -Math.PI * 0.5, 0.0, Math.PI);
+
+    b = new LatLonBounds();
+    c1.getBounds(b);
+    c2.getBounds(b);
+    assertTrue(b.checkNoLongitudeBound());
+    assertTrue(b.checkNoTopLatitudeBound());
+    assertTrue(b.checkNoBottomLatitudeBound());
+    //assertEquals(-Math.PI * 0.5,b.getLeftLongitude(),0.000001);
+    //assertEquals(Math.PI,b.getRightLongitude(),0.000001);
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoCircleTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoCircleTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoCircleTest.java
new file mode 100755
index 0000000..186bf4c
--- /dev/null
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoCircleTest.java
@@ -0,0 +1,410 @@
+/*
+ * 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.spatial3d.geom;
+
+import org.apache.lucene.util.LuceneTestCase;
+import org.junit.Test;
+
+public class GeoCircleTest extends LuceneTestCase {
+
+  @Test
+  public void testCircleDistance() {
+    GeoCircle c;
+    GeoPoint gp;
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, -0.5, 0.1);
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
+    assertEquals(Double.MAX_VALUE, c.computeDistance(DistanceStyle.ARC,gp), 0.0);
+    assertEquals(Double.MAX_VALUE, c.computeDistance(DistanceStyle.NORMAL,gp), 0.0);
+    assertEquals(Double.MAX_VALUE, c.computeDistance(DistanceStyle.NORMAL,gp), 0.0);
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
+    assertEquals(0.0, c.computeDistance(DistanceStyle.ARC,gp), 0.000001);
+    assertEquals(0.0, c.computeDistance(DistanceStyle.NORMAL,gp), 0.000001);
+    assertEquals(0.0, c.computeDistance(DistanceStyle.NORMAL,gp), 0.000001);
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, -0.5);
+    assertEquals(0.05, c.computeDistance(DistanceStyle.ARC,gp), 0.000001);
+    assertEquals(0.049995, c.computeDistance(DistanceStyle.LINEAR,gp), 0.000001);
+    assertEquals(0.049979, c.computeDistance(DistanceStyle.NORMAL,gp), 0.000001);
+  }
+
+  @Test
+  public void testCircleFullWorld() {
+    GeoCircle c;
+    GeoPoint gp;
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, -0.5, Math.PI);
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.55);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.45);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.5, 0.0);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
+    assertTrue(c.isWithin(gp));
+    LatLonBounds b = new LatLonBounds();
+    c.getBounds(b);
+    assertTrue(b.checkNoLongitudeBound());
+    assertTrue(b.checkNoTopLatitudeBound());
+    assertTrue(b.checkNoBottomLatitudeBound());
+  }
+
+  @Test
+  public void testCirclePointWithin() {
+    GeoCircle c;
+    GeoPoint gp;
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, -0.5, 0.1);
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
+    assertFalse(c.isWithin(gp));
+    assertEquals(0.4,c.computeOutsideDistance(DistanceStyle.ARC,gp),1e-12);
+    assertEquals(0.12,c.computeOutsideDistance(DistanceStyle.NORMAL,gp),0.01);
+    assertEquals(0.4,c.computeOutsideDistance(DistanceStyle.LINEAR,gp),0.01);
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.55);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.45);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.5, 0.0);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
+    assertFalse(c.isWithin(gp));
+  }
+
+  @Test
+  public void testCircleBounds() {
+    GeoCircle c;
+    LatLonBounds b;
+    XYZBounds xyzb;
+    GeoArea area;
+    GeoPoint p1;
+    GeoPoint p2;
+    int relationship;
+
+    // ...
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84, -0.005931145568901605, -0.001942031539653079, 1.2991918568260272E-4);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84, 1.001098377143621, 1.001100011578687, -0.00207467080358696, -0.0018136665346280983, -0.006067808248760161, -0.005807683665759485);
+    p1 = new GeoPoint(PlanetModel.WGS84, -0.00591253844632244, -0.0020069187259065093);
+    p2 = new GeoPoint(1.001099185736782, -0.0020091272069679327, -0.005919118245803968);
+    assertTrue(c.isWithin(p1));
+    assertTrue(area.isWithin(p1));
+    relationship = area.getRelationship(c);
+    assertTrue(relationship != GeoArea.DISJOINT);
+
+    // Twelfth BKD discovered failure
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84,-0.00824379317765984,-0.0011677469001838581,0.0011530035396910402);
+    p1 = new GeoPoint(PlanetModel.WGS84,-0.006505092992723671,0.007654282718327381);
+    p2 = new GeoPoint(1.0010681673665647,0.007662608264336381,-0.006512324005914593);
+    assertTrue(!c.isWithin(p1));
+    assertTrue(!c.isWithin(p2));
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84, 
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    relationship = area.getRelationship(c);
+    assertTrue(relationship == GeoArea.OVERLAPS || relationship == GeoArea.WITHIN);
+    // Point is actually outside the bounds, and outside the shape
+    assertTrue(!area.isWithin(p1));
+    // Approximate point the same
+    assertTrue(!area.isWithin(p2));
+    
+    // Eleventh BKD discovered failure
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE,-0.004431288600558495,-0.003687846671278374,1.704543429364245E-8);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    //System.err.println(area);
+    relationship = area.getRelationship(c);
+    assertTrue(GeoArea.WITHIN == relationship || GeoArea.OVERLAPS == relationship);
+
+    // Tenth BKD discovered failure
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84,-0.0018829770647349636,-0.001969499061382591,1.3045439293158305E-5);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84, 
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    //System.err.println(area);
+    relationship = area.getRelationship(c);
+    assertTrue(GeoArea.WITHIN == relationship || GeoArea.OVERLAPS == relationship);
+
+    // Ninth BKD discovered failure
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE,-4.211990380885122E-5,-0.0022958453508173044,1.4318475623498535E-5);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    //System.err.println(area);
+    relationship = area.getRelationship(c);
+    assertTrue(GeoArea.WITHIN == relationship || GeoArea.OVERLAPS == relationship);
+    
+    // Eighth BKD discovered failure
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE,0.005321278689117842,-0.00216937368755372,1.5306034422500785E-4);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    //System.err.println(area);
+    relationship = area.getRelationship(c);
+    assertTrue(GeoArea.WITHIN == relationship || GeoArea.OVERLAPS == relationship);
+
+    // Seventh BKD discovered failure
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE,-0.0021627146783861745, -0.0017298167021592304,2.0818312293195752E-4);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    //System.err.println(area);
+    relationship = area.getRelationship(c);
+    assertTrue(GeoArea.WITHIN == relationship || GeoArea.OVERLAPS == relationship);
+
+    // Sixth BKD discovered failure
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84,-0.006450320645814321,0.004660694205115142,0.00489710732634323);
+    //xyzb = new XYZBounds();
+    //c.getBounds(xyzb);
+    //System.err.println("xmin="+xyzb.getMinimumX()+", xmax="+xyzb.getMaximumX()+",ymin="+xyzb.getMinimumY()+", ymax="+xyzb.getMaximumY()+",zmin="+xyzb.getMinimumZ()+", zmax="+xyzb.getMaximumZ());
+    //xmin=1.0010356621420726, xmax=1.0011141249179447,ymin=-2.5326643901354566E-4, ymax=0.009584741915757169,zmin=-0.011359874956269283, zmax=-0.0015549504447452225
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84,1.0010822580620098,1.0010945779732867,0.007079167343247293,0.007541006774427837,-0.0021855011220022575,-0.001896122718181518);
+    assertTrue(GeoArea.CONTAINS != area.getRelationship(c));
+    /*
+    p1 = new GeoPoint(1.0010893045436076,0.007380935180644008,-0.002140671370616495);
+    // This has a different bounding box, so we can't use it.
+    //p2 = new GeoPoint(PlanetModel.WGS84,-0.002164069780096702, 0.007505617500830066);
+    p2 = new GeoPoint(PlanetModel.WGS84,p1.getLatitude(),p1.getLongitude());
+    assertTrue(PlanetModel.WGS84.pointOnSurface(p2));
+    assertTrue(!c.isWithin(p2));
+    assertTrue(!area.isWithin(p2));
+    assertTrue(!c.isWithin(p1));
+    assertTrue(PlanetModel.WGS84.pointOnSurface(p1)); // This fails
+    assertTrue(!area.isWithin(p1)); // This fails
+    */
+    
+    // Fifth BKD discovered failure
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -0.004282454525970269, -1.6739831367422277E-4, 1.959639723134033E-6);
+    assertTrue(c.isWithin(c.getEdgePoints()[0]));
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE,
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    assertTrue(GeoArea.WITHIN == area.getRelationship(c) || GeoArea.OVERLAPS == area.getRelationship(c));
+    
+    // Fourth BKD discovered failure
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -0.0048795517261255, 0.004053904306995974, 5.93699764258874E-6);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE,
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    assertTrue(GeoArea.WITHIN == area.getRelationship(c) || GeoArea.OVERLAPS == area.getRelationship(c));
+    
+    // Yet another test case from BKD
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84, 0.006229478708446979, 0.005570196723795424, 3.840276763694387E-5);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84,
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    p1 = new GeoPoint(PlanetModel.WGS84, 0.006224927111830945, 0.005597367237251763);
+    p2 = new GeoPoint(1.0010836083810235, 0.005603490759433942, 0.006231850560862502);
+    assertTrue(PlanetModel.WGS84.pointOnSurface(p1));
+    //assertTrue(PlanetModel.WGS84.pointOnSurface(p2));
+    assertTrue(c.isWithin(p1));
+    assertTrue(c.isWithin(p2));
+    assertTrue(area.isWithin(p1));
+    assertTrue(area.isWithin(p2));
+    
+    // Another test case from BKD
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -0.005955031040627789, -0.0029274772647399153, 1.601488279374338E-5);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE,
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    
+    relationship = area.getRelationship(c);
+    assertTrue(relationship == GeoArea.WITHIN || relationship == GeoArea.OVERLAPS);
+    
+    // Test case from BKD
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -0.765816119338, 0.991848766844, 0.8153163226330487);
+    p1 = new GeoPoint(0.7692262265236023, -0.055089298115534646, -0.6365973465711254);
+    assertTrue(c.isWithin(p1));
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    assertTrue(p1.x >= xyzb.getMinimumX() && p1.x <= xyzb.getMaximumX());
+    assertTrue(p1.y >= xyzb.getMinimumY() && p1.y <= xyzb.getMaximumY());
+    assertTrue(p1.z >= xyzb.getMinimumZ() && p1.z <= xyzb.getMaximumZ());
+    
+    // Vertical circle cases
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, -0.5, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(-0.6, b.getLeftLongitude(), 0.000001);
+    assertEquals(-0.4, b.getRightLongitude(), 0.000001);
+    assertEquals(-0.1, b.getMinLatitude(), 0.000001);
+    assertEquals(0.1, b.getMaxLatitude(), 0.000001);
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, 0.5, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(0.4, b.getLeftLongitude(), 0.000001);
+    assertEquals(0.6, b.getRightLongitude(), 0.000001);
+    assertEquals(-0.1, b.getMinLatitude(), 0.000001);
+    assertEquals(0.1, b.getMaxLatitude(), 0.000001);
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(-0.1, b.getLeftLongitude(), 0.000001);
+    assertEquals(0.1, b.getRightLongitude(), 0.000001);
+    assertEquals(-0.1, b.getMinLatitude(), 0.000001);
+    assertEquals(0.1, b.getMaxLatitude(), 0.000001);
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.0, Math.PI, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(Math.PI - 0.1, b.getLeftLongitude(), 0.000001);
+    assertEquals(-Math.PI + 0.1, b.getRightLongitude(), 0.000001);
+    assertEquals(-0.1, b.getMinLatitude(), 0.000001);
+    assertEquals(0.1, b.getMaxLatitude(), 0.000001);
+    // Horizontal circle cases
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, Math.PI * 0.5, 0.0, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertTrue(b.checkNoLongitudeBound());
+    assertTrue(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(Math.PI * 0.5 - 0.1, b.getMinLatitude(), 0.000001);
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertTrue(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertTrue(b.checkNoBottomLatitudeBound());
+    assertEquals(-Math.PI * 0.5 + 0.1, b.getMaxLatitude(), 0.000001);
+
+    // Now do a somewhat tilted plane, facing different directions.
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, 0.0, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
+    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
+    assertEquals(-0.1, b.getLeftLongitude(), 0.00001);
+    assertEquals(0.1, b.getRightLongitude(), 0.00001);
+
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, Math.PI, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
+    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
+    assertEquals(Math.PI - 0.1, b.getLeftLongitude(), 0.00001);
+    assertEquals(-Math.PI + 0.1, b.getRightLongitude(), 0.00001);
+
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, Math.PI * 0.5, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
+    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
+    assertEquals(Math.PI * 0.5 - 0.1, b.getLeftLongitude(), 0.00001);
+    assertEquals(Math.PI * 0.5 + 0.1, b.getRightLongitude(), 0.00001);
+
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, -Math.PI * 0.5, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
+    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
+    assertEquals(-Math.PI * 0.5 - 0.1, b.getLeftLongitude(), 0.00001);
+    assertEquals(-Math.PI * 0.5 + 0.1, b.getRightLongitude(), 0.00001);
+
+    // Slightly tilted, PI/4 direction.
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, Math.PI * 0.25, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
+    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
+    assertEquals(Math.PI * 0.25 - 0.1, b.getLeftLongitude(), 0.00001);
+    assertEquals(Math.PI * 0.25 + 0.1, b.getRightLongitude(), 0.00001);
+
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, -Math.PI * 0.25, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
+    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
+    assertEquals(-Math.PI * 0.25 - 0.1, b.getLeftLongitude(), 0.00001);
+    assertEquals(-Math.PI * 0.25 + 0.1, b.getRightLongitude(), 0.00001);
+
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -0.01, Math.PI * 0.25, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(0.09, b.getMaxLatitude(), 0.000001);
+    assertEquals(-0.11, b.getMinLatitude(), 0.000001);
+    assertEquals(Math.PI * 0.25 - 0.1, b.getLeftLongitude(), 0.00001);
+    assertEquals(Math.PI * 0.25 + 0.1, b.getRightLongitude(), 0.00001);
+
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, -0.01, -Math.PI * 0.25, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(0.09, b.getMaxLatitude(), 0.000001);
+    assertEquals(-0.11, b.getMinLatitude(), 0.000001);
+    assertEquals(-Math.PI * 0.25 - 0.1, b.getLeftLongitude(), 0.00001);
+    assertEquals(-Math.PI * 0.25 + 0.1, b.getRightLongitude(), 0.00001);
+
+    // Now do a somewhat tilted plane.
+    c = GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, 0.01, -0.5, 0.1);
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(0.11, b.getMaxLatitude(), 0.000001);
+    assertEquals(-0.09, b.getMinLatitude(), 0.000001);
+    assertEquals(-0.6, b.getLeftLongitude(), 0.00001);
+    assertEquals(-0.4, b.getRightLongitude(), 0.00001);
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoConvexPolygonTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoConvexPolygonTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoConvexPolygonTest.java
new file mode 100755
index 0000000..a6ca404
--- /dev/null
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoConvexPolygonTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.spatial3d.geom;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class GeoConvexPolygonTest {
+
+
+  @Test
+  public void testPolygonPointWithin() {
+    GeoConvexPolygon c;
+    GeoPoint gp;
+    c = new GeoConvexPolygon(PlanetModel.SPHERE, -0.1, -0.5);
+    c.addPoint(0.0, -0.6, false);
+    c.addPoint(0.1, -0.5, false);
+    c.addPoint(0.0, -0.4, false);
+    c.done(false);
+    // Sample some points within
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.55);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.45);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.05, -0.5);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, -0.5);
+    assertTrue(c.isWithin(gp));
+    // Sample some nearby points outside, and compute distance-to-shape for them as well
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.65);
+    assertFalse(c.isWithin(gp));
+    assertEquals(0.05,c.computeOutsideDistance(DistanceStyle.ARC,gp),1e-12);
+    assertEquals(0.05,c.computeOutsideDistance(DistanceStyle.NORMAL,gp),1e-3);
+    assertEquals(0.05,c.computeOutsideDistance(DistanceStyle.LINEAR,gp),1e-3);
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.35);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.15, -0.5);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.15, -0.5);
+    assertFalse(c.isWithin(gp));
+    // Random points outside
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.5, 0.0);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
+    assertFalse(c.isWithin(gp));
+  }
+
+  @Test
+  public void testPolygonBounds() {
+    GeoConvexPolygon c;
+    LatLonBounds b;
+
+    c = new GeoConvexPolygon(PlanetModel.SPHERE, -0.1, -0.5);
+    c.addPoint(0.0, -0.6, false);
+    c.addPoint(0.1, -0.5, false);
+    c.addPoint(0.0, -0.4, false);
+    c.done(false);
+
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(-0.6, b.getLeftLongitude(), 0.000001);
+    assertEquals(-0.4, b.getRightLongitude(), 0.000001);
+    assertEquals(-0.1, b.getMinLatitude(), 0.000001);
+    assertEquals(0.1, b.getMaxLatitude(), 0.000001);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoModelTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoModelTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoModelTest.java
new file mode 100644
index 0000000..d5fcbdd
--- /dev/null
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoModelTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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.spatial3d.geom;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test basic plane functionality.
+ */
+public class GeoModelTest {
+
+  protected final static PlanetModel scaledModel = new PlanetModel(1.2,1.5);
+  
+  @Test
+  public void testBasicCircle() {
+    // The point of this test is just to make sure nothing blows up doing normal things with a quite non-spherical model
+    // Make sure that the north pole is in the circle, and south pole isn't
+    final GeoPoint northPole = new GeoPoint(scaledModel, Math.PI * 0.5, 0.0);
+    final GeoPoint southPole = new GeoPoint(scaledModel, -Math.PI * 0.5, 0.0);
+    final GeoPoint point1 = new GeoPoint(scaledModel, Math.PI * 0.25, 0.0);
+    final GeoPoint point2 = new GeoPoint(scaledModel, Math.PI * 0.125, 0.0);
+    
+    GeoCircle circle = new GeoStandardCircle(scaledModel, Math.PI * 0.5, 0.0, 0.01);
+    assertTrue(circle.isWithin(northPole));
+    assertFalse(circle.isWithin(southPole));
+    assertFalse(circle.isWithin(point1));
+    LatLonBounds bounds;
+    bounds = new LatLonBounds();
+    circle.getBounds(bounds);
+    assertTrue(bounds.checkNoLongitudeBound());
+    assertTrue(bounds.checkNoTopLatitudeBound());
+    assertFalse(bounds.checkNoBottomLatitudeBound());
+    assertEquals(Math.PI * 0.5 - 0.01, bounds.getMinLatitude(), 0.01);
+
+    circle = new GeoStandardCircle(scaledModel, Math.PI * 0.25, 0.0, 0.01);
+    assertTrue(circle.isWithin(point1));
+    assertFalse(circle.isWithin(northPole));
+    assertFalse(circle.isWithin(southPole));
+    bounds = new LatLonBounds();
+    circle.getBounds(bounds);
+    assertFalse(bounds.checkNoTopLatitudeBound());
+    assertFalse(bounds.checkNoLongitudeBound());
+    assertFalse(bounds.checkNoBottomLatitudeBound());
+    assertEquals(Math.PI * 0.25 + 0.01, bounds.getMaxLatitude(), 0.00001);
+    assertEquals(Math.PI * 0.25 - 0.01, bounds.getMinLatitude(), 0.00001);
+    assertEquals(-0.0125, bounds.getLeftLongitude(), 0.0001);
+    assertEquals(0.0125, bounds.getRightLongitude(), 0.0001);
+
+    circle = new GeoStandardCircle(scaledModel, Math.PI * 0.125, 0.0, 0.01);
+    assertTrue(circle.isWithin(point2));
+    assertFalse(circle.isWithin(northPole));
+    assertFalse(circle.isWithin(southPole));
+    bounds = new LatLonBounds();
+    circle.getBounds(bounds);
+    assertFalse(bounds.checkNoLongitudeBound());
+    assertFalse(bounds.checkNoTopLatitudeBound());
+    assertFalse(bounds.checkNoBottomLatitudeBound());
+    // Symmetric, as expected
+    assertEquals(Math.PI * 0.125 - 0.01, bounds.getMinLatitude(), 0.00001);
+    assertEquals(Math.PI * 0.125 + 0.01, bounds.getMaxLatitude(), 0.00001);
+    assertEquals(-0.0089, bounds.getLeftLongitude(), 0.0001);
+    assertEquals(0.0089, bounds.getRightLongitude(), 0.0001);
+
+  }
+
+  @Test
+  public void testBasicRectangle() {
+    final GeoBBox bbox = GeoBBoxFactory.makeGeoBBox(scaledModel, 1.0, 0.0, 0.0, 1.0);
+    final GeoPoint insidePoint = new GeoPoint(scaledModel, 0.5, 0.5);
+    assertTrue(bbox.isWithin(insidePoint));
+    final GeoPoint topOutsidePoint = new GeoPoint(scaledModel, 1.01, 0.5);
+    assertFalse(bbox.isWithin(topOutsidePoint));
+    final GeoPoint bottomOutsidePoint = new GeoPoint(scaledModel, -0.01, 0.5);
+    assertFalse(bbox.isWithin(bottomOutsidePoint));
+    final GeoPoint leftOutsidePoint = new GeoPoint(scaledModel, 0.5, -0.01);
+    assertFalse(bbox.isWithin(leftOutsidePoint));
+    final GeoPoint rightOutsidePoint = new GeoPoint(scaledModel, 0.5, 1.01);
+    assertFalse(bbox.isWithin(rightOutsidePoint));
+    final LatLonBounds bounds = new LatLonBounds();
+    bbox.getBounds(bounds);
+    assertFalse(bounds.checkNoLongitudeBound());
+    assertFalse(bounds.checkNoTopLatitudeBound());
+    assertFalse(bounds.checkNoBottomLatitudeBound());
+    assertEquals(1.0, bounds.getMaxLatitude(), 0.00001);
+    assertEquals(0.0, bounds.getMinLatitude(), 0.00001);
+    assertEquals(1.0, bounds.getRightLongitude(), 0.00001);
+    assertEquals(0.0, bounds.getLeftLongitude(), 0.00001);
+  }
+  
+}
+
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPathTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPathTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPathTest.java
new file mode 100755
index 0000000..3746069
--- /dev/null
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPathTest.java
@@ -0,0 +1,270 @@
+/*
+ * 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.spatial3d.geom;
+
+import org.junit.Test;
+
+import static java.lang.Math.toRadians;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class GeoPathTest {
+
+  @Test
+  public void testPathDistance() {
+    // Start with a really simple case
+    GeoPath p;
+    GeoPoint gp;
+    p = new GeoPath(PlanetModel.SPHERE, 0.1);
+    p.addPoint(0.0, 0.0);
+    p.addPoint(0.0, 0.1);
+    p.addPoint(0.0, 0.2);
+    p.done();
+    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.5, 0.15);
+    assertEquals(Double.MAX_VALUE, p.computeDistance(DistanceStyle.ARC,gp), 0.0);
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, 0.15);
+    assertEquals(0.15 + 0.05, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.12);
+    assertEquals(0.12 + 0.0, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.15, 0.05);
+    assertEquals(Double.MAX_VALUE, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.25);
+    assertEquals(0.20 + 0.05, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.05);
+    assertEquals(0.0 + 0.05, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
+
+    // Compute path distances now
+    p = new GeoPath(PlanetModel.SPHERE, 0.1);
+    p.addPoint(0.0, 0.0);
+    p.addPoint(0.0, 0.1);
+    p.addPoint(0.0, 0.2);
+    p.done();
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, 0.15);
+    assertEquals(0.15 + 0.05, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.12);
+    assertEquals(0.12, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
+
+    // Now try a vertical path, and make sure distances are as expected
+    p = new GeoPath(PlanetModel.SPHERE, 0.1);
+    p.addPoint(-Math.PI * 0.25, -0.5);
+    p.addPoint(Math.PI * 0.25, -0.5);
+    p.done();
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
+    assertEquals(Double.MAX_VALUE, p.computeDistance(DistanceStyle.ARC,gp), 0.0);
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.1, -1.0);
+    assertEquals(Double.MAX_VALUE, p.computeDistance(DistanceStyle.ARC,gp), 0.0);
+    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.25 + 0.05, -0.5);
+    assertEquals(Math.PI * 0.5 + 0.05, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
+    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.25 - 0.05, -0.5);
+    assertEquals(0.0 + 0.05, p.computeDistance(DistanceStyle.ARC,gp), 0.000001);
+  }
+
+  @Test
+  public void testPathPointWithin() {
+    // Tests whether we can properly detect whether a point is within a path or not
+    GeoPath p;
+    GeoPoint gp;
+    p = new GeoPath(PlanetModel.SPHERE, 0.1);
+    // Build a diagonal path crossing the equator
+    p.addPoint(-0.2, -0.2);
+    p.addPoint(0.2, 0.2);
+    p.done();
+    // Test points on the path
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.2, -0.2);
+    assertTrue(p.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
+    assertTrue(p.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.1, 0.1);
+    assertTrue(p.isWithin(gp));
+    // Test points off the path
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.2, 0.2);
+    assertFalse(p.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0);
+    assertFalse(p.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.2, -0.2);
+    assertFalse(p.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
+    assertFalse(p.isWithin(gp));
+    // Repeat the test, but across the terminator
+    p = new GeoPath(PlanetModel.SPHERE, 0.1);
+    // Build a diagonal path crossing the equator
+    p.addPoint(-0.2, Math.PI - 0.2);
+    p.addPoint(0.2, -Math.PI + 0.2);
+    p.done();
+    // Test points on the path
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.2, Math.PI - 0.2);
+    assertTrue(p.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
+    assertTrue(p.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.1, -Math.PI + 0.1);
+    assertTrue(p.isWithin(gp));
+    // Test points off the path
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.2, -Math.PI + 0.2);
+    assertFalse(p.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0);
+    assertFalse(p.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.2, Math.PI - 0.2);
+    assertFalse(p.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
+    assertFalse(p.isWithin(gp));
+
+  }
+
+  @Test
+  public void testGetRelationship() {
+    GeoArea rect;
+    GeoPath p;
+    GeoPath c;
+    GeoPoint point;
+    GeoPoint pointApprox;
+    int relationship;
+    GeoArea area;
+    PlanetModel planetModel;
+    
+    planetModel = new PlanetModel(1.151145876105594, 0.8488541238944061);
+    c = new GeoPath(planetModel, 0.008726646259971648);
+    c.addPoint(-0.6925658899376476, 0.6316613927914589);
+    c.addPoint(0.27828548161836364, 0.6785795524104564);
+    c.done();
+    point = new GeoPoint(planetModel,-0.49298555067758226, 0.9892440995026406);
+    pointApprox = new GeoPoint(0.5110940362119821, 0.7774603209946239, -0.49984312299556544);
+    area = GeoAreaFactory.makeGeoArea(planetModel, 0.49937141144985997, 0.5161765426256085, 0.3337218719537796,0.8544419570901649, -0.6347692823688085, 0.3069696588119369);
+    assertTrue(!c.isWithin(point));
+    
+    // Start by testing the basic kinds of relationship, increasing in order of difficulty.
+
+    p = new GeoPath(PlanetModel.SPHERE, 0.1);
+    p.addPoint(-0.3, -0.3);
+    p.addPoint(0.3, 0.3);
+    p.done();
+    // Easiest: The path is wholly contains the georect
+    rect = new GeoRectangle(PlanetModel.SPHERE, 0.05, -0.05, -0.05, 0.05);
+    assertEquals(GeoArea.CONTAINS, rect.getRelationship(p));
+    // Next easiest: Some endpoints of the rectangle are inside, and some are outside.
+    rect = new GeoRectangle(PlanetModel.SPHERE, 0.05, -0.05, -0.05, 0.5);
+    assertEquals(GeoArea.OVERLAPS, rect.getRelationship(p));
+    // Now, all points are outside, but the figures intersect
+    rect = new GeoRectangle(PlanetModel.SPHERE, 0.05, -0.05, -0.5, 0.5);
+    assertEquals(GeoArea.OVERLAPS, rect.getRelationship(p));
+    // Finally, all points are outside, and the figures *do not* intersect
+    rect = new GeoRectangle(PlanetModel.SPHERE, 0.5, -0.5, -0.5, 0.5);
+    assertEquals(GeoArea.WITHIN, rect.getRelationship(p));
+    // Check that segment edge overlap detection works
+    rect = new GeoRectangle(PlanetModel.SPHERE, 0.1, 0.0, -0.1, 0.0);
+    assertEquals(GeoArea.OVERLAPS, rect.getRelationship(p));
+    rect = new GeoRectangle(PlanetModel.SPHERE, 0.2, 0.1, -0.2, -0.1);
+    assertEquals(GeoArea.DISJOINT, rect.getRelationship(p));
+    // Check if overlap at endpoints behaves as expected next
+    rect = new GeoRectangle(PlanetModel.SPHERE, 0.5, -0.5, -0.5, -0.35);
+    assertEquals(GeoArea.OVERLAPS, rect.getRelationship(p));
+    rect = new GeoRectangle(PlanetModel.SPHERE, 0.5, -0.5, -0.5, -0.45);
+    assertEquals(GeoArea.DISJOINT, rect.getRelationship(p));
+
+  }
+
+  @Test
+  public void testPathBounds() {
+    GeoPath c;
+    LatLonBounds b;
+    XYZBounds xyzb;
+    GeoPoint point;
+    int relationship;
+    GeoArea area;
+    PlanetModel planetModel;
+    
+    planetModel = new PlanetModel(0.751521665790406,1.248478334209594);
+    c = new GeoPath(planetModel, 0.7504915783575618);
+    c.addPoint(0.10869761172400265, 0.08895880215465272);
+    c.addPoint(0.22467878641991612, 0.10972973084229565);
+    c.addPoint(-0.7398772468744732, -0.4465812941383364);
+    c.addPoint(-0.18462055300079366, -0.6713857796763727);
+    c.done();
+    point = new GeoPoint(planetModel,-0.626645355125733,-1.409304625439381);
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(planetModel,
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    relationship = area.getRelationship(c);
+    assertTrue(relationship == GeoArea.WITHIN || relationship == GeoArea.OVERLAPS);
+    assertTrue(area.isWithin(point));
+    // No longer true due to fixed GeoPath waypoints.
+    //assertTrue(c.isWithin(point));
+    
+    c = new GeoPath(PlanetModel.WGS84, 0.6894050545377601);
+    c.addPoint(-0.0788176065762948, 0.9431251741731624);
+    c.addPoint(0.510387871458147, 0.5327078872484678);
+    c.addPoint(-0.5624521609859962, 1.5398841746888388);
+    c.addPoint(-0.5025171434638661, -0.5895998642788894);
+    c.done();
+    point = new GeoPoint(PlanetModel.WGS84, 0.023652082107211682, 0.023131910152748437);
+    //System.err.println("Point.x = "+point.x+"; point.y="+point.y+"; point.z="+point.z);
+    assertTrue(c.isWithin(point));
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84,
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    //System.err.println("minx="+xyzb.getMinimumX()+" maxx="+xyzb.getMaximumX()+" miny="+xyzb.getMinimumY()+" maxy="+xyzb.getMaximumY()+" minz="+xyzb.getMinimumZ()+" maxz="+xyzb.getMaximumZ());
+    //System.err.println("point.x="+point.x+" point.y="+point.y+" point.z="+point.z);
+    relationship = area.getRelationship(c);
+    assertTrue(relationship == GeoArea.WITHIN || relationship == GeoArea.OVERLAPS);
+    assertTrue(area.isWithin(point));
+    
+    c = new GeoPath(PlanetModel.WGS84, 0.7766715171374766);
+    c.addPoint(-0.2751718361148076, -0.7786721269011477);
+    c.addPoint(0.5728375851539309, -1.2700115736820465);
+    c.done();
+    point = new GeoPoint(PlanetModel.WGS84, -0.01580760332365284, -0.03956004622490505);
+    assertTrue(c.isWithin(point));
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84,
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    //System.err.println("minx="+xyzb.getMinimumX()+" maxx="+xyzb.getMaximumX()+" miny="+xyzb.getMinimumY()+" maxy="+xyzb.getMaximumY()+" minz="+xyzb.getMinimumZ()+" maxz="+xyzb.getMaximumZ());
+    //System.err.println("point.x="+point.x+" point.y="+point.y+" point.z="+point.z);
+    relationship = area.getRelationship(c);
+    assertTrue(relationship == GeoArea.WITHIN || relationship == GeoArea.OVERLAPS);
+    assertTrue(area.isWithin(point));
+
+    c = new GeoPath(PlanetModel.SPHERE, 0.1);
+    c.addPoint(-0.3, -0.3);
+    c.addPoint(0.3, 0.3);
+    c.done();
+
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(-0.4046919, b.getLeftLongitude(), 0.000001);
+    assertEquals(0.4046919, b.getRightLongitude(), 0.000001);
+    assertEquals(-0.3999999, b.getMinLatitude(), 0.000001);
+    assertEquals(0.3999999, b.getMaxLatitude(), 0.000001);
+
+  }
+
+  @Test
+  public void testCoLinear() {
+    // p1: (12,-90), p2: (11, -55), (129, -90)
+    GeoPath p = new GeoPath(PlanetModel.SPHERE, 0.1);
+    p.addPoint(toRadians(-90), toRadians(12));//south pole
+    p.addPoint(toRadians(-55), toRadians(11));
+    p.addPoint(toRadians(-90), toRadians(129));//south pole again
+    p.done();//at least test this doesn't bomb like it used too -- LUCENE-6520
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPointTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPointTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPointTest.java
new file mode 100644
index 0000000..ed17928
--- /dev/null
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPointTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.spatial3d.geom;
+
+import org.apache.lucene.util.LuceneTestCase;
+import org.junit.Test;
+
+import static com.carrotsearch.randomizedtesting.RandomizedTest.randomFloat;
+
+/**
+ * Test basic GeoPoint functionality.
+ */
+public class GeoPointTest extends LuceneTestCase {
+  static final double DEGREES_TO_RADIANS =  Math.PI / 180;
+
+  @Test
+  public void testConversion() {
+    testPointRoundTrip(PlanetModel.SPHERE, 90 * DEGREES_TO_RADIANS, 0, 1e-6);
+    testPointRoundTrip(PlanetModel.SPHERE, -90 * DEGREES_TO_RADIANS, 0, 1e-6);
+    testPointRoundTrip(PlanetModel.WGS84, 90 * DEGREES_TO_RADIANS, 0, 1e-6);
+    testPointRoundTrip(PlanetModel.WGS84, -90 * 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) * DEGREES_TO_RADIANS;
+      final double pLon = (randomFloat() * 360.0 - 180.0) * 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) * DEGREES_TO_RADIANS;
+      final double p1Lon = (randomFloat() * 360.0 - 180.0) * DEGREES_TO_RADIANS;
+      final double p2Lat = (randomFloat() * 180.0 - 90.0) * DEGREES_TO_RADIANS;
+      final double p2Lon = (randomFloat() * 360.0 - 180.0) * 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/0a1951be/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
new file mode 100755
index 0000000..d9b220d
--- /dev/null
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
@@ -0,0 +1,165 @@
+/*
+ * 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.spatial3d.geom;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class GeoPolygonTest {
+
+
+  @Test
+  public void testPolygonPointWithin() {
+    GeoMembershipShape c;
+    GeoPoint gp;
+    List<GeoPoint> points;
+
+    points = new ArrayList<GeoPoint>();
+    points.add(new GeoPoint(PlanetModel.SPHERE, -0.1, -0.5));
+    points.add(new GeoPoint(PlanetModel.SPHERE, 0.0, -0.6));
+    points.add(new GeoPoint(PlanetModel.SPHERE, 0.1, -0.5));
+    points.add(new GeoPoint(PlanetModel.SPHERE, 0.0, -0.4));
+
+    c = GeoPolygonFactory.makeGeoPolygon(PlanetModel.SPHERE, points, 0);
+    // Sample some points within
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.55);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.45);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.05, -0.5);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, -0.5);
+    assertTrue(c.isWithin(gp));
+    // Sample some nearby points outside
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.65);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.35);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.15, -0.5);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.15, -0.5);
+    assertFalse(c.isWithin(gp));
+    // Random points outside
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.5, 0.0);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
+    assertFalse(c.isWithin(gp));
+
+    points = new ArrayList<GeoPoint>();
+    points.add(new GeoPoint(PlanetModel.SPHERE, -0.1, -0.5));
+    points.add(new GeoPoint(PlanetModel.SPHERE, -0.01, -0.6));
+    points.add(new GeoPoint(PlanetModel.SPHERE, -0.1, -0.7));
+    points.add(new GeoPoint(PlanetModel.SPHERE, 0.0, -0.8));
+    points.add(new GeoPoint(PlanetModel.SPHERE, 0.1, -0.7));
+    points.add(new GeoPoint(PlanetModel.SPHERE, 0.01, -0.6));
+    points.add(new GeoPoint(PlanetModel.SPHERE, 0.1, -0.5));
+    points.add(new GeoPoint(PlanetModel.SPHERE, 0.0, -0.4));
+        
+        /*
+        System.out.println("Points: ");
+        for (GeoPoint p : points) {
+            System.out.println(" "+p);
+        }
+        */
+
+    c = GeoPolygonFactory.makeGeoPolygon(PlanetModel.SPHERE, points, 0);
+    // Sample some points within
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.55);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.45);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.05, -0.5);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, -0.5);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.7);
+    assertTrue(c.isWithin(gp));
+    // Sample some nearby points outside
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.35);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.15, -0.5);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.15, -0.5);
+    assertFalse(c.isWithin(gp));
+    // Random points outside
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.5, 0.0);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
+    assertFalse(c.isWithin(gp));
+
+  }
+
+  @Test
+  public void testPolygonBounds() {
+    GeoMembershipShape c;
+    LatLonBounds b;
+    List<GeoPoint> points;
+    XYZBounds xyzb;
+    GeoPoint point;
+    GeoArea area;
+    
+    // BKD failure
+    points = new ArrayList<GeoPoint>();
+    points.add(new GeoPoint(PlanetModel.WGS84, -0.36716183577912814, 1.4836349969188696));
+    points.add(new GeoPoint(PlanetModel.WGS84, 0.7846038240742979, -0.02743348424931823));
+    points.add(new GeoPoint(PlanetModel.WGS84, -0.7376479402362607, -0.5072961758807019));
+    points.add(new GeoPoint(PlanetModel.WGS84, -0.3760415907667887, 1.4970455334565513));
+    
+    c = GeoPolygonFactory.makeGeoPolygon(PlanetModel.WGS84, points, 1);
+    
+    point = new GeoPoint(PlanetModel.WGS84, -0.01580760332365284, -0.03956004622490505);
+    assertTrue(c.isWithin(point));
+    xyzb = new XYZBounds();
+    c.getBounds(xyzb);
+    area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84,
+      xyzb.getMinimumX(), xyzb.getMaximumX(), xyzb.getMinimumY(), xyzb.getMaximumY(), xyzb.getMinimumZ(), xyzb.getMaximumZ());
+    assertTrue(area.isWithin(point));
+    
+    points = new ArrayList<GeoPoint>();
+    points.add(new GeoPoint(PlanetModel.SPHERE, -0.1, -0.5));
+    points.add(new GeoPoint(PlanetModel.SPHERE, 0.0, -0.6));
+    points.add(new GeoPoint(PlanetModel.SPHERE, 0.1, -0.5));
+    points.add(new GeoPoint(PlanetModel.SPHERE, 0.0, -0.4));
+
+    c = GeoPolygonFactory.makeGeoPolygon(PlanetModel.SPHERE, points, 0);
+
+    b = new LatLonBounds();
+    c.getBounds(b);
+    assertFalse(b.checkNoLongitudeBound());
+    assertFalse(b.checkNoTopLatitudeBound());
+    assertFalse(b.checkNoBottomLatitudeBound());
+    assertEquals(-0.6, b.getLeftLongitude(), 0.000001);
+    assertEquals(-0.4, b.getRightLongitude(), 0.000001);
+    assertEquals(-0.1, b.getMinLatitude(), 0.000001);
+    assertEquals(0.1, b.getMaxLatitude(), 0.000001);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/PlaneTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/PlaneTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/PlaneTest.java
new file mode 100644
index 0000000..91bd0c3
--- /dev/null
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/PlaneTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.spatial3d.geom;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test basic plane functionality.
+ */
+public class PlaneTest {
+
+
+  @Test
+  public void testIdenticalPlanes() {
+    final GeoPoint p = new GeoPoint(PlanetModel.SPHERE, 0.123, -0.456);
+    final Plane plane1 = new Plane(p, 0.0);
+    final Plane plane2 = new Plane(p, 0.0);
+    assertTrue(plane1.isNumericallyIdentical(plane2));
+    final Plane plane3 = new Plane(p, 0.1);
+    assertFalse(plane1.isNumericallyIdentical(plane3));
+    final Vector v1 = new Vector(0.1, -0.732, 0.9);
+    final double constant = 0.432;
+    final Vector v2 = new Vector(v1.x * constant, v1.y * constant, v1.z * constant);
+    final Plane p1 = new Plane(v1, 0.2);
+    final Plane p2 = new Plane(v2, 0.2 * constant);
+    assertTrue(p1.isNumericallyIdentical(p2));
+  }
+
+  @Test
+  public void testInterpolation() {
+    // [X=0.35168818443386646, Y=-0.19637966197066342, Z=0.9152870857244183],
+    // [X=0.5003343189532654, Y=0.522128543226148, Z=0.6906861469771293],
+
+    final GeoPoint start = new GeoPoint(0.35168818443386646, -0.19637966197066342, 0.9152870857244183);
+    final GeoPoint end = new GeoPoint(0.5003343189532654, 0.522128543226148, 0.6906861469771293);
+
+    // [A=-0.6135342247741855, B=0.21504338363863665, C=0.28188192383666794, D=0.0, side=-1.0] internal? false;
+    final Plane p = new Plane(-0.6135342247741855, 0.21504338363863665, 0.28188192383666794, 0.0);
+
+    final GeoPoint[] points = p.interpolate(start, end, new double[]{0.25, 0.50, 0.75});
+
+    for (GeoPoint point : points) {
+      assertTrue(p.evaluateIsZero(point));
+    }
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/XYZSolidTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/XYZSolidTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/XYZSolidTest.java
new file mode 100644
index 0000000..98c616e
--- /dev/null
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/XYZSolidTest.java
@@ -0,0 +1,220 @@
+/*
+ * 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.spatial3d.geom;
+
+import org.apache.lucene.util.LuceneTestCase;
+import org.junit.Test;
+
+public class XYZSolidTest extends LuceneTestCase {
+
+  @Test
+  public void testNonDegenerateRelationships() {
+    XYZSolid s;
+    GeoShape shape;
+    // Something bigger than the world
+    s = new StandardXYZSolid(PlanetModel.SPHERE, -2.0, 2.0, -2.0, 2.0, -2.0, 2.0);
+    // Any shape, except whole world, should be within.
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.WITHIN, s.getRelationship(shape));
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    // An XYZSolid represents a surface shape, which when larger than the world is in fact
+    // the entire world, so it should overlap the world.
+    assertEquals(GeoArea.OVERLAPS, s.getRelationship(shape));
+
+    // Something overlapping the world on only one side
+    s = new StandardXYZSolid(PlanetModel.SPHERE, -2.0, 0.0, -2.0, 2.0, -2.0, 2.0);
+    // Some things should be disjoint...
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, s.getRelationship(shape));
+    // And, some things should be within... 
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI, 0.1);
+    assertEquals(GeoArea.WITHIN, s.getRelationship(shape));
+    // And, some things should overlap.
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI * 0.5, 0.1);
+    assertEquals(GeoArea.OVERLAPS, s.getRelationship(shape));
+
+    // Partial world should be contained by GeoWorld object...
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.CONTAINS, s.getRelationship(shape));
+    
+    // Something inside the world
+    s = new StandardXYZSolid(PlanetModel.SPHERE, -0.1, 0.1, -0.1, 0.1, -0.1, 0.1);
+    // All shapes should be disjoint
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, s.getRelationship(shape));
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.DISJOINT, s.getRelationship(shape));
+    
+  }
+
+  @Test
+  public void testDegenerateRelationships() {
+    GeoArea solid;
+    GeoShape shape;
+    
+    // Basic test of the factory method - non-degenerate
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, -2.0, 2.0, -2.0, 2.0, -2.0, 2.0);
+    // Any shape, except whole world, should be within.
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.WITHIN, solid.getRelationship(shape));
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    // An XYZSolid represents a surface shape, which when larger than the world is in fact
+    // the entire world, so it should overlap the world.
+    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
+
+    // Build a degenerate point, not on sphere
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+    // disjoint with everything?
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+
+    // Build a degenerate point that IS on the sphere
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0);
+    // inside everything that it touches?
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+
+    // Build a shape degenerate in (x,y), which has no points on sphere
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, 0.0, 0.0, -0.1, 0.1);
+    // disjoint with everything?
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+
+    // Build a shape degenerate in (x,y) which has one point on sphere
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, 0.0, 0.0, -0.1, 1.1);
+    // inside everything that it touches?
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, Math.PI * 0.5, 0.0, 0.1);
+    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+
+    // Build a shape degenerate in (x,y) which has two points on sphere
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, 0.0, 0.0, -1.1, 1.1);
+    // inside everything that it touches?
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, Math.PI * 0.5, 0.0, 0.1);
+    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0, 0.1);
+    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
+    
+    // Build a shape degenerate in (x,z), which has no points on sphere
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, -0.1, 0.1, 0.0, 0.0);
+    // disjoint with everything?
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+
+    // Build a shape degenerate in (x,z) which has one point on sphere
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, -0.1, 1.1, 0.0, 0.0);
+    // inside everything that it touches?
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI * 0.5, 0.1);
+    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, -Math.PI * 0.5, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+
+    // Build a shape degenerate in (x,y) which has two points on sphere
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, -1.1, 1.1, 0.0, 0.0);
+    // inside everything that it touches?
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI * 0.5, 0.1);
+    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, -Math.PI * 0.5, 0.1);
+    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
+
+    // MHL for y-z check
+    
+    // Build a shape that is degenerate in x, which has zero points intersecting sphere
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, -0.1, 0.1, -0.1, 0.1);
+    // disjoint with everything?
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+
+    // Build a shape that is degenerate in x, which has zero points intersecting sphere, second variation
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, -0.1, 0.1, 1.1, 1.2);
+    // disjoint with everything?
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+
+    // Build a shape that is disjoint in X but intersects sphere in a complete circle
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, -1.1, 1.1, -1.1, 1.1);
+    // inside everything that it touches?
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI * 0.5, 0.1);
+    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, -Math.PI * 0.5, 0.1);
+    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, Math.PI * 0.5, 0.0, 0.1);
+    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0, 0.1);
+    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
+
+    // Build a shape that is disjoint in X but intersects sphere in a half circle in Y
+    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, 0.0, 1.1, -1.1, 1.1);
+    // inside everything that it touches?
+    shape = new GeoWorld(PlanetModel.SPHERE);
+    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI * 0.5, 0.1);
+    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, -Math.PI * 0.5, 0.1);
+    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, Math.PI * 0.5, 0.0, 0.1);
+    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
+    shape = new GeoStandardCircle(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0, 0.1);
+    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
+
+    // MHL for degenerate Y
+    // MHL for degenerate Z
+    
+  }
+  
+}


[05/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 0093e26)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java
new file mode 100755
index 0000000..1f2c054
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java
@@ -0,0 +1,1657 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * We know about three kinds of planes.  First kind: general plain through two points and origin
+ * Second kind: horizontal plane at specified height.  Third kind: vertical plane with specified x and y value, through origin.
+ *
+ * @lucene.experimental
+ */
+public class Plane extends Vector {
+  /** An array with no points in it */
+  protected final static GeoPoint[] NO_POINTS = new GeoPoint[0];
+  /** An array with no bounds in it */
+  protected final static Membership[] NO_BOUNDS = new Membership[0];
+  /** A vertical plane normal to the Y axis */
+  protected final static Plane normalYPlane = new Plane(0.0,1.0,0.0,0.0);
+  /** A vertical plane normal to the X axis */
+  protected final static Plane normalXPlane = new Plane(1.0,0.0,0.0,0.0);
+  /** A vertical plane normal to the Z axis */
+  protected final static Plane normalZPlane = new Plane(0.0,0.0,1.0,0.0);
+
+  /** Ax + By + Cz + D = 0 */
+  public final double D;
+
+  /**
+   * Construct a plane with all four coefficients defined.
+   *@param A is A
+   *@param B is B
+   *@param C is C
+   *@param D is D
+   */
+  public Plane(final double A, final double B, final double C, final double D) {
+    super(A, B, C);
+    this.D = D;
+  }
+
+  /**
+   * Construct a plane through two points and origin.
+   *
+   * @param A is the first point (origin based).
+   * @param B is the second point (origin based).
+   */
+  public Plane(final Vector A, final Vector B) {
+    super(A, B);
+    D = 0.0;
+  }
+
+  /**
+   * Construct a horizontal plane at a specified Z.
+   *
+   * @param planetModel is the planet model.
+   * @param sinLat is the sin(latitude).
+   */
+  public Plane(final PlanetModel planetModel, final double sinLat) {
+    super(0.0, 0.0, 1.0);
+    D = -sinLat * computeDesiredEllipsoidMagnitude(planetModel, sinLat);
+  }
+
+  /**
+   * Construct a vertical plane through a specified
+   * x, y and origin.
+   *
+   * @param x is the specified x value.
+   * @param y is the specified y value.
+   */
+  public Plane(final double x, final double y) {
+    super(y, -x, 0.0);
+    D = 0.0;
+  }
+
+  /**
+   * Construct a plane with a specific vector, and D offset
+   * from origin.
+   * @param v is the normal vector.
+   * @param D is the D offset from the origin.
+   */
+  public Plane(final Vector v, final double D) {
+    super(v.x, v.y, v.z);
+    this.D = D;
+  }
+
+  /** Construct the most accurate normalized plane through an x-y point and including the Z axis.
+   * If none of the points can determine the plane, return null.
+   * @param planePoints is a set of points to choose from.  The best one for constructing the most precise plane is picked.
+   * @return the plane
+   */
+  public static Plane constructNormalizedZPlane(final Vector... planePoints) {
+    // Pick the best one (with the greatest x-y distance)
+    double bestDistance = 0.0;
+    Vector bestPoint = null;
+    for (final Vector point : planePoints) {
+      final double pointDist = point.x * point.x + point.y * point.y;
+      if (pointDist > bestDistance) {
+        bestDistance = pointDist;
+        bestPoint = point;
+      }
+    }
+    return constructNormalizedZPlane(bestPoint.x, bestPoint.y);
+  }
+
+  /** Construct the most accurate normalized plane through an x-z point and including the Y axis.
+   * If none of the points can determine the plane, return null.
+   * @param planePoints is a set of points to choose from.  The best one for constructing the most precise plane is picked.
+   * @return the plane
+   */
+  public static Plane constructNormalizedYPlane(final Vector... planePoints) {
+    // Pick the best one (with the greatest x-z distance)
+    double bestDistance = 0.0;
+    Vector bestPoint = null;
+    for (final Vector point : planePoints) {
+      final double pointDist = point.x * point.x + point.z * point.z;
+      if (pointDist > bestDistance) {
+        bestDistance = pointDist;
+        bestPoint = point;
+      }
+    }
+    return constructNormalizedYPlane(bestPoint.x, bestPoint.z, 0.0);
+  }
+
+  /** Construct the most accurate normalized plane through an y-z point and including the X axis.
+   * If none of the points can determine the plane, return null.
+   * @param planePoints is a set of points to choose from.  The best one for constructing the most precise plane is picked.
+   * @return the plane
+   */
+  public static Plane constructNormalizedXPlane(final Vector... planePoints) {
+    // Pick the best one (with the greatest y-z distance)
+    double bestDistance = 0.0;
+    Vector bestPoint = null;
+    for (final Vector point : planePoints) {
+      final double pointDist = point.y * point.y + point.z * point.z;
+      if (pointDist > bestDistance) {
+        bestDistance = pointDist;
+        bestPoint = point;
+      }
+    }
+    return constructNormalizedXPlane(bestPoint.y, bestPoint.z, 0.0);
+  }
+
+  /** Construct a normalized plane through an x-y point and including the Z axis.
+   * If the x-y point is at (0,0), return null.
+   * @param x is the x value.
+   * @param y is the y value.
+   * @return a plane passing through the Z axis and (x,y,0).
+   */
+  public static Plane constructNormalizedZPlane(final double x, final double y) {
+    if (Math.abs(x) < MINIMUM_RESOLUTION && Math.abs(y) < MINIMUM_RESOLUTION)
+      return null;
+    final double denom = 1.0 / Math.sqrt(x*x + y*y);
+    return new Plane(y * denom, -x * denom, 0.0, 0.0);
+  }
+
+  /** Construct a normalized plane through an x-z point and parallel to the Y axis.
+   * If the x-z point is at (0,0), return null.
+   * @param x is the x value.
+   * @param z is the z value.
+   * @param DValue is the offset from the origin for the plane.
+   * @return a plane parallel to the Y axis and perpendicular to the x and z values given.
+   */
+  public static Plane constructNormalizedYPlane(final double x, final double z, final double DValue) {
+    if (Math.abs(x) < MINIMUM_RESOLUTION && Math.abs(z) < MINIMUM_RESOLUTION)
+      return null;
+    final double denom = 1.0 / Math.sqrt(x*x + z*z);
+    return new Plane(z * denom, 0.0, -x * denom, DValue);
+  }
+
+  /** Construct a normalized plane through a y-z point and parallel to the X axis.
+   * If the y-z point is at (0,0), return null.
+   * @param y is the y value.
+   * @param z is the z value.
+   * @param DValue is the offset from the origin for the plane.
+   * @return a plane parallel to the X axis and perpendicular to the y and z values given.
+   */
+  public static Plane constructNormalizedXPlane(final double y, final double z, final double DValue) {
+    if (Math.abs(y) < MINIMUM_RESOLUTION && Math.abs(z) < MINIMUM_RESOLUTION)
+      return null;
+    final double denom = 1.0 / Math.sqrt(y*y + z*z);
+    return new Plane(0.0, z * denom, -y * denom, DValue);
+  }
+  
+  /**
+   * Evaluate the plane equation for a given point, as represented
+   * by a vector.
+   *
+   * @param v is the vector.
+   * @return the result of the evaluation.
+   */
+  public double evaluate(final Vector v) {
+    return dotProduct(v) + D;
+  }
+
+  /**
+   * Evaluate the plane equation for a given point, as represented
+   * by a vector.
+   * @param x is the x value.
+   * @param y is the y value.
+   * @param z is the z value.
+   * @return the result of the evaluation.
+   */
+  public double evaluate(final double x, final double y, final double z) {
+    return dotProduct(x, y, z) + D;
+  }
+
+  /**
+   * Evaluate the plane equation for a given point, as represented
+   * by a vector.
+   *
+   * @param v is the vector.
+   * @return true if the result is on the plane.
+   */
+  public boolean evaluateIsZero(final Vector v) {
+    return Math.abs(evaluate(v)) < MINIMUM_RESOLUTION;
+  }
+
+  /**
+   * Evaluate the plane equation for a given point, as represented
+   * by a vector.
+   *
+   * @param x is the x value.
+   * @param y is the y value.
+   * @param z is the z value.
+   * @return true if the result is on the plane.
+   */
+  public boolean evaluateIsZero(final double x, final double y, final double z) {
+    return Math.abs(evaluate(x, y, z)) < MINIMUM_RESOLUTION;
+  }
+
+  /**
+   * Build a normalized plane, so that the vector is normalized.
+   *
+   * @return the normalized plane object, or null if the plane is indeterminate.
+   */
+  public Plane normalize() {
+    Vector normVect = super.normalize();
+    if (normVect == null)
+      return null;
+    return new Plane(normVect, this.D);
+  }
+
+  /** Compute arc distance from plane to a vector expressed with a {@link GeoPoint}.
+   *  @see #arcDistance(PlanetModel, double, double, double, Membership...) */
+  public double arcDistance(final PlanetModel planetModel, final GeoPoint v, final Membership... bounds) {
+    return arcDistance(planetModel, v.x, v.y, v.z, bounds);
+  }
+    
+  /**
+   * Compute arc distance from plane to a vector.
+   * @param planetModel is the planet model.
+   * @param x is the x vector value.
+   * @param y is the y vector value.
+   * @param z is the z vector value.
+   * @param bounds are the bounds which constrain the intersection point.
+   * @return the arc distance.
+   */
+  public double arcDistance(final PlanetModel planetModel, final double x, final double y, final double z, final Membership... bounds) {
+
+    if (evaluateIsZero(x,y,z)) {
+      if (meetsAllBounds(x,y,z, bounds))
+        return 0.0;
+      return Double.MAX_VALUE;
+    }
+    
+    // First, compute the perpendicular plane.
+    final Plane perpPlane = new Plane(this.y * z - this.z * y, this.z * x - this.x * z, this.x * y - this.y * x, 0.0);
+
+    // We need to compute the intersection of two planes on the geo surface: this one, and its perpendicular.
+    // Then, we need to choose which of the two points we want to compute the distance to.  We pick the
+    // shorter distance always.
+    
+    final GeoPoint[] intersectionPoints = findIntersections(planetModel, perpPlane);
+    
+    // For each point, compute a linear distance, and take the minimum of them
+    double minDistance = Double.MAX_VALUE;
+    
+    for (final GeoPoint intersectionPoint : intersectionPoints) {
+      if (meetsAllBounds(intersectionPoint, bounds)) {
+        final double theDistance = intersectionPoint.arcDistance(x,y,z);
+        if (theDistance < minDistance) {
+          minDistance = theDistance;
+        }
+      }
+    }
+    return minDistance;
+
+  }
+
+  /**
+   * Compute normal distance from plane to a vector.
+   * @param v is the vector.
+   * @param bounds are the bounds which constrain the intersection point.
+   * @return the normal distance.
+   */
+  public double normalDistance(final Vector v, final Membership... bounds) {
+    return normalDistance(v.x, v.y, v.z, bounds);
+  }
+    
+  /**
+   * Compute normal distance from plane to a vector.
+   * @param x is the vector x.
+   * @param y is the vector y.
+   * @param z is the vector z.
+   * @param bounds are the bounds which constrain the intersection point.
+   * @return the normal distance.
+   */
+  public double normalDistance(final double x, final double y, final double z, final Membership... bounds) {
+
+    final double dist = evaluate(x,y,z);
+    final double perpX = x - dist * this.x;
+    final double perpY = y - dist * this.y;
+    final double perpZ = z - dist * this.z;
+
+    if (!meetsAllBounds(perpX, perpY, perpZ, bounds)) {
+      return Double.MAX_VALUE;
+    }
+    
+    return Math.abs(dist);
+  }
+  
+  /**
+   * Compute normal distance squared from plane to a vector.
+   * @param v is the vector.
+   * @param bounds are the bounds which constrain the intersection point.
+   * @return the normal distance squared.
+   */
+  public double normalDistanceSquared(final Vector v, final Membership... bounds) {
+    return normalDistanceSquared(v.x, v.y, v.z, bounds);
+  }
+  
+  /**
+   * Compute normal distance squared from plane to a vector.
+   * @param x is the vector x.
+   * @param y is the vector y.
+   * @param z is the vector z.
+   * @param bounds are the bounds which constrain the intersection point.
+   * @return the normal distance squared.
+   */
+  public double normalDistanceSquared(final double x, final double y, final double z, final Membership... bounds) {
+    final double normal = normalDistance(x,y,z,bounds);
+    if (normal == Double.MAX_VALUE)
+      return normal;
+    return normal * normal;
+  }
+
+  /**
+   * Compute linear distance from plane to a vector.  This is defined
+   * as the distance from the given point to the nearest intersection of 
+   * this plane with the planet surface.
+   * @param planetModel is the planet model.
+   * @param v is the point.
+   * @param bounds are the bounds which constrain the intersection point.
+   * @return the linear distance.
+   */
+  public double linearDistance(final PlanetModel planetModel, final GeoPoint v, final Membership... bounds) {
+    return linearDistance(planetModel, v.x, v.y, v.z, bounds);
+  }
+    
+  /**
+   * Compute linear distance from plane to a vector.  This is defined
+   * as the distance from the given point to the nearest intersection of 
+   * this plane with the planet surface.
+   * @param planetModel is the planet model.
+   * @param x is the vector x.
+   * @param y is the vector y.
+   * @param z is the vector z.
+   * @param bounds are the bounds which constrain the intersection point.
+   * @return the linear distance.
+   */
+  public double linearDistance(final PlanetModel planetModel, final double x, final double y, final double z, final Membership... bounds) {
+    if (evaluateIsZero(x,y,z)) {
+      if (meetsAllBounds(x,y,z, bounds))
+        return 0.0;
+      return Double.MAX_VALUE;
+    }
+    
+    // First, compute the perpendicular plane.
+    final Plane perpPlane = new Plane(this.y * z - this.z * y, this.z * x - this.x * z, this.x * y - this.y * x, 0.0);
+
+    // We need to compute the intersection of two planes on the geo surface: this one, and its perpendicular.
+    // Then, we need to choose which of the two points we want to compute the distance to.  We pick the
+    // shorter distance always.
+    
+    final GeoPoint[] intersectionPoints = findIntersections(planetModel, perpPlane);
+    
+    // For each point, compute a linear distance, and take the minimum of them
+    double minDistance = Double.MAX_VALUE;
+    
+    for (final GeoPoint intersectionPoint : intersectionPoints) {
+      if (meetsAllBounds(intersectionPoint, bounds)) {
+        final double theDistance = intersectionPoint.linearDistance(x,y,z);
+        if (theDistance < minDistance) {
+          minDistance = theDistance;
+        }
+      }
+    }
+    return minDistance;
+  }
+      
+  /**
+   * Compute linear distance squared from plane to a vector.  This is defined
+   * as the distance from the given point to the nearest intersection of 
+   * this plane with the planet surface.
+   * @param planetModel is the planet model.
+   * @param v is the point.
+   * @param bounds are the bounds which constrain the intersection point.
+   * @return the linear distance squared.
+   */
+  public double linearDistanceSquared(final PlanetModel planetModel, final GeoPoint v, final Membership... bounds) {
+    return linearDistanceSquared(planetModel, v.x, v.y, v.z, bounds);
+  }
+  
+  /**
+   * Compute linear distance squared from plane to a vector.  This is defined
+   * as the distance from the given point to the nearest intersection of 
+   * this plane with the planet surface.
+   * @param planetModel is the planet model.
+   * @param x is the vector x.
+   * @param y is the vector y.
+   * @param z is the vector z.
+   * @param bounds are the bounds which constrain the intersection point.
+   * @return the linear distance squared.
+   */
+  public double linearDistanceSquared(final PlanetModel planetModel, final double x, final double y, final double z, final Membership... bounds) {
+    final double linearDistance = linearDistance(planetModel, x, y, z, bounds);
+    return linearDistance * linearDistance;
+  }
+
+  /**
+   * Find points on the boundary of the intersection of a plane and the unit sphere,
+   * given a starting point, and ending point, and a list of proportions of the arc (e.g. 0.25, 0.5, 0.75).
+   * The angle between the starting point and ending point is assumed to be less than pi.
+   * @param start is the start point.
+   * @param end is the end point.
+   * @param proportions is an array of fractional proportions measured between start and end.
+   * @return an array of points corresponding to the proportions passed in.
+   */
+  public GeoPoint[] interpolate(final GeoPoint start, final GeoPoint end, final double[] proportions) {
+    // Steps:
+    // (1) Translate (x0,y0,z0) of endpoints into origin-centered place:
+    // x1 = x0 + D*A
+    // y1 = y0 + D*B
+    // z1 = z0 + D*C
+    // (2) Rotate counterclockwise in x-y:
+    // ra = -atan2(B,A)
+    // x2 = x1 cos ra - y1 sin ra
+    // y2 = x1 sin ra + y1 cos ra
+    // z2 = z1
+    // Faster:
+    // cos ra = A/sqrt(A^2+B^2+C^2)
+    // sin ra = -B/sqrt(A^2+B^2+C^2)
+    // cos (-ra) = A/sqrt(A^2+B^2+C^2)
+    // sin (-ra) = B/sqrt(A^2+B^2+C^2)
+    // (3) Rotate clockwise in x-z:
+    // ha = pi/2 - asin(C/sqrt(A^2+B^2+C^2))
+    // x3 = x2 cos ha - z2 sin ha
+    // y3 = y2
+    // z3 = x2 sin ha + z2 cos ha
+    // At this point, z3 should be zero.
+    // Faster:
+    // sin(ha) = cos(asin(C/sqrt(A^2+B^2+C^2))) = sqrt(1 - C^2/(A^2+B^2+C^2)) = sqrt(A^2+B^2)/sqrt(A^2+B^2+C^2)
+    // cos(ha) = sin(asin(C/sqrt(A^2+B^2+C^2))) = C/sqrt(A^2+B^2+C^2)
+    // (4) Compute interpolations by getting longitudes of original points
+    // la = atan2(y3,x3)
+    // (5) Rotate new points (xN0, yN0, zN0) counter-clockwise in x-z:
+    // ha = -(pi - asin(C/sqrt(A^2+B^2+C^2)))
+    // xN1 = xN0 cos ha - zN0 sin ha
+    // yN1 = yN0
+    // zN1 = xN0 sin ha + zN0 cos ha
+    // (6) Rotate new points clockwise in x-y:
+    // ra = atan2(B,A)
+    // xN2 = xN1 cos ra - yN1 sin ra
+    // yN2 = xN1 sin ra + yN1 cos ra
+    // zN2 = zN1
+    // (7) Translate new points:
+    // xN3 = xN2 - D*A
+    // yN3 = yN2 - D*B
+    // zN3 = zN2 - D*C
+
+    // First, calculate the angles and their sin/cos values
+    double A = x;
+    double B = y;
+    double C = z;
+
+    // Translation amounts
+    final double transX = -D * A;
+    final double transY = -D * B;
+    final double transZ = -D * C;
+
+    double cosRA;
+    double sinRA;
+    double cosHA;
+    double sinHA;
+
+    double magnitude = magnitude();
+    if (magnitude >= MINIMUM_RESOLUTION) {
+      final double denom = 1.0 / magnitude;
+      A *= denom;
+      B *= denom;
+      C *= denom;
+
+      // cos ra = A/sqrt(A^2+B^2+C^2)
+      // sin ra = -B/sqrt(A^2+B^2+C^2)
+      // cos (-ra) = A/sqrt(A^2+B^2+C^2)
+      // sin (-ra) = B/sqrt(A^2+B^2+C^2)
+      final double xyMagnitude = Math.sqrt(A * A + B * B);
+      if (xyMagnitude >= MINIMUM_RESOLUTION) {
+        final double xyDenom = 1.0 / xyMagnitude;
+        cosRA = A * xyDenom;
+        sinRA = -B * xyDenom;
+      } else {
+        cosRA = 1.0;
+        sinRA = 0.0;
+      }
+
+      // sin(ha) = cos(asin(C/sqrt(A^2+B^2+C^2))) = sqrt(1 - C^2/(A^2+B^2+C^2)) = sqrt(A^2+B^2)/sqrt(A^2+B^2+C^2)
+      // cos(ha) = sin(asin(C/sqrt(A^2+B^2+C^2))) = C/sqrt(A^2+B^2+C^2)
+      sinHA = xyMagnitude;
+      cosHA = C;
+    } else {
+      cosRA = 1.0;
+      sinRA = 0.0;
+      cosHA = 1.0;
+      sinHA = 0.0;
+    }
+
+    // Forward-translate the start and end points
+    final Vector modifiedStart = modify(start, transX, transY, transZ, sinRA, cosRA, sinHA, cosHA);
+    final Vector modifiedEnd = modify(end, transX, transY, transZ, sinRA, cosRA, sinHA, cosHA);
+    if (Math.abs(modifiedStart.z) >= MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("Start point was not on plane: " + modifiedStart.z);
+    if (Math.abs(modifiedEnd.z) >= MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("End point was not on plane: " + modifiedEnd.z);
+
+    // Compute the angular distance between start and end point
+    final double startAngle = Math.atan2(modifiedStart.y, modifiedStart.x);
+    final double endAngle = Math.atan2(modifiedEnd.y, modifiedEnd.x);
+
+    final double startMagnitude = Math.sqrt(modifiedStart.x * modifiedStart.x + modifiedStart.y * modifiedStart.y);
+    double delta;
+
+    double newEndAngle = endAngle;
+    while (newEndAngle < startAngle) {
+      newEndAngle += Math.PI * 2.0;
+    }
+
+    if (newEndAngle - startAngle <= Math.PI) {
+      delta = newEndAngle - startAngle;
+    } else {
+      double newStartAngle = startAngle;
+      while (newStartAngle < endAngle) {
+        newStartAngle += Math.PI * 2.0;
+      }
+      delta = newStartAngle - endAngle;
+    }
+
+    final GeoPoint[] returnValues = new GeoPoint[proportions.length];
+    for (int i = 0; i < returnValues.length; i++) {
+      final double newAngle = startAngle + proportions[i] * delta;
+      final double sinNewAngle = Math.sin(newAngle);
+      final double cosNewAngle = Math.cos(newAngle);
+      final Vector newVector = new Vector(cosNewAngle * startMagnitude, sinNewAngle * startMagnitude, 0.0);
+      returnValues[i] = reverseModify(newVector, transX, transY, transZ, sinRA, cosRA, sinHA, cosHA);
+    }
+
+    return returnValues;
+  }
+
+  /**
+   * Modify a point to produce a vector in translated/rotated space.
+   * @param start is the start point.
+   * @param transX is the translation x value.
+   * @param transY is the translation y value.
+   * @param transZ is the translation z value.
+   * @param sinRA is the sine of the ascension angle.
+   * @param cosRA is the cosine of the ascension angle.
+   * @param sinHA is the sine of the height angle.
+   * @param cosHA is the cosine of the height angle.
+   * @return the modified point.
+   */
+  protected static Vector modify(final GeoPoint start, final double transX, final double transY, final double transZ,
+                                 final double sinRA, final double cosRA, final double sinHA, final double cosHA) {
+    return start.translate(transX, transY, transZ).rotateXY(sinRA, cosRA).rotateXZ(sinHA, cosHA);
+  }
+
+  /**
+   * Reverse modify a point to produce a GeoPoint in normal space.
+   * @param point is the translated point.
+   * @param transX is the translation x value.
+   * @param transY is the translation y value.
+   * @param transZ is the translation z value.
+   * @param sinRA is the sine of the ascension angle.
+   * @param cosRA is the cosine of the ascension angle.
+   * @param sinHA is the sine of the height angle.
+   * @param cosHA is the cosine of the height angle.
+   * @return the original point.
+   */
+  protected static GeoPoint reverseModify(final Vector point, final double transX, final double transY, final double transZ,
+                                          final double sinRA, final double cosRA, final double sinHA, final double cosHA) {
+    final Vector result = point.rotateXZ(-sinHA, cosHA).rotateXY(-sinRA, cosRA).translate(-transX, -transY, -transZ);
+    return new GeoPoint(result.x, result.y, result.z);
+  }
+
+  /**
+   * Public version of findIntersections.
+   * @param planetModel is the planet model.
+   * @param q is the plane to intersect with.
+   * @param bounds are the bounds to consider to determine legal intersection points.
+   * @return the set of legal intersection points.
+   */
+  public GeoPoint[] findIntersections(final PlanetModel planetModel, final Plane q, final Membership... bounds) {
+    if (isNumericallyIdentical(q)) {
+      return null;
+    }
+    return findIntersections(planetModel, q, bounds, NO_BOUNDS);
+  }
+  
+  /**
+   * Find the intersection points between two planes, given a set of bounds.
+   *
+   * @param planetModel is the planet model to use in finding points.
+   * @param q          is the plane to intersect with.
+   * @param bounds     is the set of bounds.
+   * @param moreBounds is another set of bounds.
+   * @return the intersection point(s) on the unit sphere, if there are any.
+   */
+  protected GeoPoint[] findIntersections(final PlanetModel planetModel, final Plane q, final Membership[] bounds, final Membership[] moreBounds) {
+    //System.err.println("Looking for intersection between plane "+this+" and plane "+q+" within bounds");
+    // Unnormalized, unchecked...
+    final Vector lineVector = new Vector(y * q.z - z * q.y, z * q.x - x * q.z, x * q.y - y * q.x);
+    if (Math.abs(lineVector.x) < MINIMUM_RESOLUTION && Math.abs(lineVector.y) < MINIMUM_RESOLUTION && Math.abs(lineVector.z) < MINIMUM_RESOLUTION) {
+      // Degenerate case: parallel planes
+      //System.err.println(" planes are parallel - no intersection");
+      return NO_POINTS;
+    }
+
+    // The line will have the equation: A t + A0 = x, B t + B0 = y, C t + C0 = z.
+    // We have A, B, and C.  In order to come up with A0, B0, and C0, we need to find a point that is on both planes.
+    // To do this, we find the largest vector value (either x, y, or z), and look for a point that solves both plane equations
+    // simultaneous.  For example, let's say that the vector is (0.5,0.5,1), and the two plane equations are:
+    // 0.7 x + 0.3 y + 0.1 z + 0.0 = 0
+    // and
+    // 0.9 x - 0.1 y + 0.2 z + 4.0 = 0
+    // Then we'd pick z = 0, so the equations to solve for x and y would be:
+    // 0.7 x + 0.3y = 0.0
+    // 0.9 x - 0.1y = -4.0
+    // ... which can readily be solved using standard linear algebra.  Generally:
+    // Q0 x + R0 y = S0
+    // Q1 x + R1 y = S1
+    // ... can be solved by Cramer's rule:
+    // x = det(S0 R0 / S1 R1) / det(Q0 R0 / Q1 R1)
+    // y = det(Q0 S0 / Q1 S1) / det(Q0 R0 / Q1 R1)
+    // ... where det( a b / c d ) = ad - bc, so:
+    // x = (S0 * R1 - R0 * S1) / (Q0 * R1 - R0 * Q1)
+    // y = (Q0 * S1 - S0 * Q1) / (Q0 * R1 - R0 * Q1)
+    double x0;
+    double y0;
+    double z0;
+    // We try to maximize the determinant in the denominator
+    final double denomYZ = this.y * q.z - this.z * q.y;
+    final double denomXZ = this.x * q.z - this.z * q.x;
+    final double denomXY = this.x * q.y - this.y * q.x;
+    if (Math.abs(denomYZ) >= Math.abs(denomXZ) && Math.abs(denomYZ) >= Math.abs(denomXY)) {
+      // X is the biggest, so our point will have x0 = 0.0
+      if (Math.abs(denomYZ) < MINIMUM_RESOLUTION_SQUARED) {
+        //System.err.println(" Denominator is zero: no intersection");
+        return NO_POINTS;
+      }
+      final double denom = 1.0 / denomYZ;
+      x0 = 0.0;
+      y0 = (-this.D * q.z - this.z * -q.D) * denom;
+      z0 = (this.y * -q.D + this.D * q.y) * denom;
+    } else if (Math.abs(denomXZ) >= Math.abs(denomXY) && Math.abs(denomXZ) >= Math.abs(denomYZ)) {
+      // Y is the biggest, so y0 = 0.0
+      if (Math.abs(denomXZ) < MINIMUM_RESOLUTION_SQUARED) {
+        //System.err.println(" Denominator is zero: no intersection");
+        return NO_POINTS;
+      }
+      final double denom = 1.0 / denomXZ;
+      x0 = (-this.D * q.z - this.z * -q.D) * denom;
+      y0 = 0.0;
+      z0 = (this.x * -q.D + this.D * q.x) * denom;
+    } else {
+      // Z is the biggest, so Z0 = 0.0
+      if (Math.abs(denomXY) < MINIMUM_RESOLUTION_SQUARED) {
+        //System.err.println(" Denominator is zero: no intersection");
+        return NO_POINTS;
+      }
+      final double denom = 1.0 / denomXY;
+      x0 = (-this.D * q.y - this.y * -q.D) * denom;
+      y0 = (this.x * -q.D + this.D * q.x) * denom;
+      z0 = 0.0;
+    }
+
+    // Once an intersecting line is determined, the next step is to intersect that line with the ellipsoid, which
+    // will yield zero, one, or two points.
+    // The ellipsoid equation: 1,0 = x^2/a^2 + y^2/b^2 + z^2/c^2
+    // 1.0 = (At+A0)^2/a^2 + (Bt+B0)^2/b^2 + (Ct+C0)^2/c^2
+    // A^2 t^2 / a^2 + 2AA0t / a^2 + A0^2 / a^2 + B^2 t^2 / b^2 + 2BB0t / b^2 + B0^2 / b^2 + C^2 t^2 / c^2 + 2CC0t / c^2 + C0^2 / c^2  - 1,0 = 0.0
+    // [A^2 / a^2 + B^2 / b^2 + C^2 / c^2] t^2 + [2AA0 / a^2 + 2BB0 / b^2 + 2CC0 / c^2] t + [A0^2 / a^2 + B0^2 / b^2 + C0^2 / c^2 - 1,0] = 0.0
+    // Use the quadratic formula to determine t values and candidate point(s)
+    final double A = lineVector.x * lineVector.x * planetModel.inverseAbSquared +
+      lineVector.y * lineVector.y * planetModel.inverseAbSquared +
+      lineVector.z * lineVector.z * planetModel.inverseCSquared;
+    final double B = 2.0 * (lineVector.x * x0 * planetModel.inverseAbSquared + lineVector.y * y0 * planetModel.inverseAbSquared + lineVector.z * z0 * planetModel.inverseCSquared);
+    final double C = x0 * x0 * planetModel.inverseAbSquared + y0 * y0 * planetModel.inverseAbSquared + z0 * z0 * planetModel.inverseCSquared - 1.0;
+
+    final double BsquaredMinus = B * B - 4.0 * A * C;
+    if (Math.abs(BsquaredMinus) < MINIMUM_RESOLUTION_SQUARED) {
+      //System.err.println(" One point of intersection");
+      final double inverse2A = 1.0 / (2.0 * A);
+      // One solution only
+      final double t = -B * inverse2A;
+      GeoPoint point = new GeoPoint(lineVector.x * t + x0, lineVector.y * t + y0, lineVector.z * t + z0);
+      //System.err.println("  point: "+point);
+      //verifyPoint(planetModel, point, q);
+      if (point.isWithin(bounds, moreBounds))
+        return new GeoPoint[]{point};
+      return NO_POINTS;
+    } else if (BsquaredMinus > 0.0) {
+      //System.err.println(" Two points of intersection");
+      final double inverse2A = 1.0 / (2.0 * A);
+      // Two solutions
+      final double sqrtTerm = Math.sqrt(BsquaredMinus);
+      final double t1 = (-B + sqrtTerm) * inverse2A;
+      final double t2 = (-B - sqrtTerm) * inverse2A;
+      GeoPoint point1 = new GeoPoint(lineVector.x * t1 + x0, lineVector.y * t1 + y0, lineVector.z * t1 + z0);
+      GeoPoint point2 = new GeoPoint(lineVector.x * t2 + x0, lineVector.y * t2 + y0, lineVector.z * t2 + z0);
+      //verifyPoint(planetModel, point1, q);
+      //verifyPoint(planetModel, point2, q);
+      //System.err.println("  "+point1+" and "+point2);
+      if (point1.isWithin(bounds, moreBounds)) {
+        if (point2.isWithin(bounds, moreBounds))
+          return new GeoPoint[]{point1, point2};
+        return new GeoPoint[]{point1};
+      }
+      if (point2.isWithin(bounds, moreBounds))
+        return new GeoPoint[]{point2};
+      return NO_POINTS;
+    } else {
+      //System.err.println(" no solutions - no intersection");
+      return NO_POINTS;
+    }
+  }
+
+  /*
+  protected void verifyPoint(final PlanetModel planetModel, final GeoPoint point, final Plane q) {
+    if (!evaluateIsZero(point))
+      throw new RuntimeException("Intersection point not on original plane; point="+point+", plane="+this);
+    if (!q.evaluateIsZero(point))
+      throw new RuntimeException("Intersection point not on intersected plane; point="+point+", plane="+q);
+    if (Math.abs(point.x * point.x * planetModel.inverseASquared + point.y * point.y * planetModel.inverseBSquared + point.z * point.z * planetModel.inverseCSquared - 1.0) >= MINIMUM_RESOLUTION) 
+      throw new RuntimeException("Intersection point not on ellipsoid; point="+point);
+  }
+  */
+
+  /**
+   * Accumulate (x,y,z) bounds information for this plane, intersected with the unit sphere.
+   * Updates min/max information, using max/min points found
+   * within the specified bounds.
+   *
+   * @param planetModel is the planet model to use in determining bounds.
+   * @param boundsInfo is the xyz info to update with additional bounding information.
+   * @param bounds     are the surfaces delineating what's inside the shape.
+   */
+  public void recordBounds(final PlanetModel planetModel, final XYZBounds boundsInfo, final Membership... bounds) {
+    // Basic plan is to do three intersections of the plane and the planet.
+    // For min/max x, we intersect a vertical plane such that y = 0.
+    // For min/max y, we intersect a vertical plane such that x = 0.
+    // For min/max z, we intersect a vertical plane that is chosen to go through the high point of the arc.
+    // For clarity, load local variables with good names
+    final double A = this.x;
+    final double B = this.y;
+    final double C = this.z;
+
+    // Do Z.  This can be done simply because it is symmetrical.
+    if (!boundsInfo.isSmallestMinZ(planetModel) || !boundsInfo.isLargestMaxZ(planetModel)) {
+      //System.err.println("    computing Z bound");
+      // Compute Z bounds for this arc
+      // With ellipsoids, we really have only one viable way to do this computation.
+      // Specifically, we compute an appropriate vertical plane, based on the current plane's x-y orientation, and
+      // then intersect it with this one and with the ellipsoid.  This gives us zero, one, or two points to use
+      // as bounds.
+      // There is one special case: horizontal circles.  These require TWO vertical planes: one for the x, and one for
+      // the y, and we use all four resulting points in the bounds computation.
+      if ((Math.abs(A) >= MINIMUM_RESOLUTION || Math.abs(B) >= MINIMUM_RESOLUTION)) {
+        // NOT a degenerate case
+        //System.err.println("    not degenerate");
+        final Plane normalizedZPlane = constructNormalizedZPlane(A,B);
+        final GeoPoint[] points = findIntersections(planetModel, normalizedZPlane, bounds, NO_BOUNDS);
+        for (final GeoPoint point : points) {
+          assert planetModel.pointOnSurface(point);
+          //System.err.println("      Point = "+point+"; this.evaluate(point)="+this.evaluate(point)+"; normalizedZPlane.evaluate(point)="+normalizedZPlane.evaluate(point));
+          addPoint(boundsInfo, bounds, point);
+        }
+      } else {
+        // Since a==b==0, any plane including the Z axis suffices.
+        //System.err.println("      Perpendicular to z");
+        final GeoPoint[] points = findIntersections(planetModel, normalYPlane, NO_BOUNDS, NO_BOUNDS);
+        boundsInfo.addZValue(points[0]);
+      }
+    }
+
+    // First, compute common subexpressions
+    final double k = 1.0 / ((x*x + y*y)*planetModel.ab*planetModel.ab + z*z*planetModel.c*planetModel.c);
+    final double abSquared = planetModel.ab * planetModel.ab;
+    final double cSquared = planetModel.c * planetModel.c;
+    final double ASquared = A * A;
+    final double BSquared = B * B;
+    final double CSquared = C * C;
+    
+    final double r = 2.0*D*k;
+    final double rSquared = r * r;
+    
+    if (!boundsInfo.isSmallestMinX(planetModel) || !boundsInfo.isLargestMaxX(planetModel)) {
+      // For min/max x, we need to use lagrange multipliers.
+      //
+      // For this, we need grad(F(x,y,z)) = (dF/dx, dF/dy, dF/dz).
+      //
+      // Minimize and maximize f(x,y,z) = x, with respect to g(x,y,z) = Ax + By + Cz - D and h(x,y,z) = x^2/ab^2 + y^2/ab^2 + z^2/c^2 - 1
+      //
+      // grad(f(x,y,z)) = (1,0,0)
+      // grad(g(x,y,z)) = (A,B,C)
+      // grad(h(x,y,z)) = (2x/ab^2,2y/ab^2,2z/c^2)
+      //
+      // Equations we need to simultaneously solve:
+      // 
+      // grad(f(x,y,z)) = l * grad(g(x,y,z)) + m * grad(h(x,y,z))
+      // g(x,y,z) = 0
+      // h(x,y,z) = 0
+      // 
+      // Equations:
+      // 1 = l*A + m*2x/ab^2
+      // 0 = l*B + m*2y/ab^2
+      // 0 = l*C + m*2z/c^2
+      // Ax + By + Cz + D = 0
+      // x^2/ab^2 + y^2/ab^2 + z^2/c^2 - 1 = 0
+      // 
+      // Solve for x,y,z in terms of (l, m):
+      // 
+      // x = ((1 - l*A) * ab^2 ) / (2 * m)
+      // y = (-l*B * ab^2) / ( 2 * m)
+      // z = (-l*C * c^2)/ (2 * m)
+      // 
+      // Two equations, two unknowns:
+      // 
+      // A * (((1 - l*A) * ab^2 ) / (2 * m)) + B * ((-l*B * ab^2) / ( 2 * m)) + C * ((-l*C * c^2)/ (2 * m)) + D = 0
+      // 
+      // and
+      // 
+      // (((1 - l*A) * ab^2 ) / (2 * m))^2/ab^2 + ((-l*B * ab^2) / ( 2 * m))^2/ab^2 + ((-l*C * c^2)/ (2 * m))^2/c^2 - 1 = 0
+      // 
+      // Simple: solve for l and m, then find x from it.
+      // 
+      // (a) Use first equation to find l in terms of m.
+      // 
+      // A * (((1 - l*A) * ab^2 ) / (2 * m)) + B * ((-l*B * ab^2) / ( 2 * m)) + C * ((-l*C * c^2)/ (2 * m)) + D = 0
+      // A * ((1 - l*A) * ab^2 ) + B * (-l*B * ab^2) + C * (-l*C * c^2) + D * 2 * m = 0
+      // A * ab^2 - l*A^2* ab^2 - B^2 * l * ab^2 - C^2 * l * c^2 + D * 2 * m = 0
+      // - l *(A^2* ab^2 + B^2 * ab^2 + C^2 * c^2) + (A * ab^2 + D * 2 * m) = 0
+      // l = (A * ab^2 + D * 2 * m) / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
+      // l = A * ab^2 / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2) + m * 2 * D / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
+      // 
+      // For convenience:
+      // 
+      // k = 1.0 / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
+      // 
+      // Then:
+      // 
+      // l = A * ab^2 * k + m * 2 * D * k
+      // l = k * (A*ab^2 + m*2*D)
+      //
+      // For further convenience:
+      //
+      // q = A*ab^2*k
+      // r = 2*D*k
+      //
+      // l = (r*m + q)
+      // l^2 = (r^2 * m^2 + 2*r*m*q + q^2)
+      // 
+      // (b) Simplify the second equation before substitution
+      // 
+      // (((1 - l*A) * ab^2 ) / (2 * m))^2/ab^2 + ((-l*B * ab^2) / ( 2 * m))^2/ab^2 + ((-l*C * c^2)/ (2 * m))^2/c^2 - 1 = 0
+      // ((1 - l*A) * ab^2 )^2/ab^2 + (-l*B * ab^2)^2/ab^2 + (-l*C * c^2)^2/c^2 = 4 * m^2
+      // (1 - l*A)^2 * ab^2 + (-l*B)^2 * ab^2 + (-l*C)^2 * c^2 = 4 * m^2
+      // (1 - 2*l*A + l^2*A^2) * ab^2 + l^2*B^2 * ab^2 + l^2*C^2 * c^2 = 4 * m^2
+      // ab^2 - 2*A*ab^2*l + A^2*ab^2*l^2 + B^2*ab^2*l^2 + C^2*c^2*l^2 - 4*m^2 = 0
+      // 
+      // (c) Substitute for l, l^2
+      //
+      // ab^2 - 2*A*ab^2*(r*m + q) + A^2*ab^2*(r^2 * m^2 + 2*r*m*q + q^2) + B^2*ab^2*(r^2 * m^2 + 2*r*m*q + q^2) + C^2*c^2*(r^2 * m^2 + 2*r*m*q + q^2) - 4*m^2 = 0
+      // ab^2 - 2*A*ab^2*r*m - 2*A*ab^2*q + A^2*ab^2*r^2*m^2 + 2*A^2*ab^2*r*q*m +
+      //        A^2*ab^2*q^2 + B^2*ab^2*r^2*m^2 + 2*B^2*ab^2*r*q*m + B^2*ab^2*q^2 + C^2*c^2*r^2*m^2 + 2*C^2*c^2*r*q*m + C^2*c^2*q^2 - 4*m^2 = 0
+      //
+      // (d) Group
+      //
+      // m^2 * [A^2*ab^2*r^2 + B^2*ab^2*r^2 + C^2*c^2*r^2 - 4] +
+      // m * [- 2*A*ab^2*r + 2*A^2*ab^2*r*q + 2*B^2*ab^2*r*q + 2*C^2*c^2*r*q] +
+      // [ab^2 - 2*A*ab^2*q + A^2*ab^2*q^2 + B^2*ab^2*q^2 + C^2*c^2*q^2]  =  0
+      
+      //System.err.println("    computing X bound");
+      
+      // Useful subexpressions for this bound
+      final double q = A*abSquared*k;
+      final double qSquared = q * q;
+
+      // Quadratic equation
+      final double a = ASquared*abSquared*rSquared + BSquared*abSquared*rSquared + CSquared*cSquared*rSquared - 4.0;
+      final double b = - 2.0*A*abSquared*r + 2.0*ASquared*abSquared*r*q + 2.0*BSquared*abSquared*r*q + 2.0*CSquared*cSquared*r*q;
+      final double c = abSquared - 2.0*A*abSquared*q + ASquared*abSquared*qSquared + BSquared*abSquared*qSquared + CSquared*cSquared*qSquared;
+      
+      if (Math.abs(a) >= MINIMUM_RESOLUTION_SQUARED) {
+        final double sqrtTerm = b*b - 4.0*a*c;
+        if (Math.abs(sqrtTerm) < MINIMUM_RESOLUTION_SQUARED) {
+          // One solution
+          final double m = -b / (2.0 * a);
+          final double l = r * m + q;
+          // x = ((1 - l*A) * ab^2 ) / (2 * m)
+          // y = (-l*B * ab^2) / ( 2 * m)
+          // z = (-l*C * c^2)/ (2 * m)
+          final double denom0 = 0.5 / m;
+          final GeoPoint thePoint = new GeoPoint((1.0-l*A) * abSquared * denom0, -l*B * abSquared * denom0, -l*C * cSquared * denom0);
+          //Math is not quite accurate enough for this
+          //assert planetModel.pointOnSurface(thePoint): "Point: "+thePoint+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
+          //  (thePoint.x*thePoint.x*planetModel.inverseAb*planetModel.inverseAb + thePoint.y*thePoint.y*planetModel.inverseAb*planetModel.inverseAb + thePoint.z*thePoint.z*planetModel.inverseC*planetModel.inverseC);
+          //assert evaluateIsZero(thePoint): "Evaluation of point: "+evaluate(thePoint);
+          addPoint(boundsInfo, bounds, thePoint);
+        } else if (sqrtTerm > 0.0) {
+          // Two solutions
+          final double sqrtResult = Math.sqrt(sqrtTerm);
+          final double commonDenom = 0.5/a;
+          final double m1 = (-b + sqrtResult) * commonDenom;
+          assert Math.abs(a * m1 * m1 + b * m1 + c) < MINIMUM_RESOLUTION;
+          final double m2 = (-b - sqrtResult) * commonDenom;
+          assert Math.abs(a * m2 * m2 + b * m2 + c) < MINIMUM_RESOLUTION;
+          final double l1 = r * m1 + q;
+          final double l2 = r * m2 + q;
+          // x = ((1 - l*A) * ab^2 ) / (2 * m)
+          // y = (-l*B * ab^2) / ( 2 * m)
+          // z = (-l*C * c^2)/ (2 * m)
+          final double denom1 = 0.5 / m1;
+          final double denom2 = 0.5 / m2;
+          final GeoPoint thePoint1 = new GeoPoint((1.0-l1*A) * abSquared * denom1, -l1*B * abSquared * denom1, -l1*C * cSquared * denom1);
+          final GeoPoint thePoint2 = new GeoPoint((1.0-l2*A) * abSquared * denom2, -l2*B * abSquared * denom2, -l2*C * cSquared * denom2);
+          //Math is not quite accurate enough for this
+          //assert planetModel.pointOnSurface(thePoint1): "Point1: "+thePoint1+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
+          //  (thePoint1.x*thePoint1.x*planetModel.inverseAb*planetModel.inverseAb + thePoint1.y*thePoint1.y*planetModel.inverseAb*planetModel.inverseAb + thePoint1.z*thePoint1.z*planetModel.inverseC*planetModel.inverseC);
+          //assert planetModel.pointOnSurface(thePoint2): "Point1: "+thePoint2+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
+          //  (thePoint2.x*thePoint2.x*planetModel.inverseAb*planetModel.inverseAb + thePoint2.y*thePoint2.y*planetModel.inverseAb*planetModel.inverseAb + thePoint2.z*thePoint2.z*planetModel.inverseC*planetModel.inverseC);
+          //assert evaluateIsZero(thePoint1): "Evaluation of point1: "+evaluate(thePoint1);
+          //assert evaluateIsZero(thePoint2): "Evaluation of point2: "+evaluate(thePoint2);
+          addPoint(boundsInfo, bounds, thePoint1);
+          addPoint(boundsInfo, bounds, thePoint2);
+        } else {
+          // No solutions
+        }
+      } else if (Math.abs(b) > MINIMUM_RESOLUTION_SQUARED) {
+        //System.err.println("Not x quadratic");
+        // a = 0, so m = - c / b
+        final double m = -c / b;
+        final double l = r * m + q;
+        // x = ((1 - l*A) * ab^2 ) / (2 * m)
+        // y = (-l*B * ab^2) / ( 2 * m)
+        // z = (-l*C * c^2)/ (2 * m)
+        final double denom0 = 0.5 / m;
+        final GeoPoint thePoint = new GeoPoint((1.0-l*A) * abSquared * denom0, -l*B * abSquared * denom0, -l*C * cSquared * denom0);
+        //Math is not quite accurate enough for this
+        //assert planetModel.pointOnSurface(thePoint): "Point: "+thePoint+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
+        //  (thePoint.x*thePoint.x*planetModel.inverseAb*planetModel.inverseAb + thePoint.y*thePoint.y*planetModel.inverseAb*planetModel.inverseAb + thePoint.z*thePoint.z*planetModel.inverseC*planetModel.inverseC);
+        //assert evaluateIsZero(thePoint): "Evaluation of point: "+evaluate(thePoint);
+        addPoint(boundsInfo, bounds, thePoint);
+      } else {
+        // Something went very wrong; a = b = 0
+      }
+    }
+    
+    // Do Y
+    if (!boundsInfo.isSmallestMinY(planetModel) || !boundsInfo.isLargestMaxY(planetModel)) {
+      // For min/max x, we need to use lagrange multipliers.
+      //
+      // For this, we need grad(F(x,y,z)) = (dF/dx, dF/dy, dF/dz).
+      //
+      // Minimize and maximize f(x,y,z) = y, with respect to g(x,y,z) = Ax + By + Cz - D and h(x,y,z) = x^2/ab^2 + y^2/ab^2 + z^2/c^2 - 1
+      //
+      // grad(f(x,y,z)) = (0,1,0)
+      // grad(g(x,y,z)) = (A,B,C)
+      // grad(h(x,y,z)) = (2x/ab^2,2y/ab^2,2z/c^2)
+      //
+      // Equations we need to simultaneously solve:
+      // 
+      // grad(f(x,y,z)) = l * grad(g(x,y,z)) + m * grad(h(x,y,z))
+      // g(x,y,z) = 0
+      // h(x,y,z) = 0
+      // 
+      // Equations:
+      // 0 = l*A + m*2x/ab^2
+      // 1 = l*B + m*2y/ab^2
+      // 0 = l*C + m*2z/c^2
+      // Ax + By + Cz + D = 0
+      // x^2/ab^2 + y^2/ab^2 + z^2/c^2 - 1 = 0
+      // 
+      // Solve for x,y,z in terms of (l, m):
+      // 
+      // x = (-l*A * ab^2 ) / (2 * m)
+      // y = ((1 - l*B) * ab^2) / ( 2 * m)
+      // z = (-l*C * c^2)/ (2 * m)
+      // 
+      // Two equations, two unknowns:
+      // 
+      // A * ((-l*A * ab^2 ) / (2 * m)) + B * (((1 - l*B) * ab^2) / ( 2 * m)) + C * ((-l*C * c^2)/ (2 * m)) + D = 0
+      // 
+      // and
+      // 
+      // ((-l*A * ab^2 ) / (2 * m))^2/ab^2 + (((1 - l*B) * ab^2) / ( 2 * m))^2/ab^2 + ((-l*C * c^2)/ (2 * m))^2/c^2 - 1 = 0
+      // 
+      // Simple: solve for l and m, then find y from it.
+      // 
+      // (a) Use first equation to find l in terms of m.
+      // 
+      // A * ((-l*A * ab^2 ) / (2 * m)) + B * (((1 - l*B) * ab^2) / ( 2 * m)) + C * ((-l*C * c^2)/ (2 * m)) + D = 0
+      // A * (-l*A * ab^2 ) + B * ((1-l*B) * ab^2) + C * (-l*C * c^2) + D * 2 * m = 0
+      // -A^2*l*ab^2 + B*ab^2 - l*B^2*ab^2 - C^2*l*c^2 + D*2*m = 0
+      // - l *(A^2* ab^2 + B^2 * ab^2 + C^2 * c^2) + (B * ab^2 + D * 2 * m) = 0
+      // l = (B * ab^2 + D * 2 * m) / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
+      // l = B * ab^2 / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2) + m * 2 * D / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
+      // 
+      // For convenience:
+      // 
+      // k = 1.0 / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
+      // 
+      // Then:
+      // 
+      // l = B * ab^2 * k + m * 2 * D * k
+      // l = k * (B*ab^2 + m*2*D)
+      //
+      // For further convenience:
+      //
+      // q = B*ab^2*k
+      // r = 2*D*k
+      //
+      // l = (r*m + q)
+      // l^2 = (r^2 * m^2 + 2*r*m*q + q^2)
+      // 
+      // (b) Simplify the second equation before substitution
+      // 
+      // ((-l*A * ab^2 ) / (2 * m))^2/ab^2 + (((1 - l*B) * ab^2) / ( 2 * m))^2/ab^2 + ((-l*C * c^2)/ (2 * m))^2/c^2 - 1 = 0
+      // (-l*A * ab^2 )^2/ab^2 + ((1 - l*B) * ab^2)^2/ab^2 + (-l*C * c^2)^2/c^2 = 4 * m^2
+      // (-l*A)^2 * ab^2 + (1 - l*B)^2 * ab^2 + (-l*C)^2 * c^2 = 4 * m^2
+      // l^2*A^2 * ab^2 + (1 - 2*l*B + l^2*B^2) * ab^2 + l^2*C^2 * c^2 = 4 * m^2
+      // A^2*ab^2*l^2 + ab^2 - 2*B*ab^2*l + B^2*ab^2*l^2 + C^2*c^2*l^2 - 4*m^2 = 0
+      // 
+      // (c) Substitute for l, l^2
+      //
+      // A^2*ab^2*(r^2 * m^2 + 2*r*m*q + q^2) + ab^2 - 2*B*ab^2*(r*m + q) + B^2*ab^2*(r^2 * m^2 + 2*r*m*q + q^2) + C^2*c^2*(r^2 * m^2 + 2*r*m*q + q^2) - 4*m^2 = 0
+      // A^2*ab^2*r^2*m^2 + 2*A^2*ab^2*r*q*m + A^2*ab^2*q^2 + ab^2 - 2*B*ab^2*r*m - 2*B*ab^2*q + B^2*ab^2*r^2*m^2 +
+      //    2*B^2*ab^2*r*q*m + B^2*ab^2*q^2 + C^2*c^2*r^2*m^2 + 2*C^2*c^2*r*q*m + C^2*c^2*q^2 - 4*m^2 = 0
+      //
+      // (d) Group
+      //
+      // m^2 * [A^2*ab^2*r^2 + B^2*ab^2*r^2 + C^2*c^2*r^2 - 4] +
+      // m * [2*A^2*ab^2*r*q - 2*B*ab^2*r + 2*B^2*ab^2*r*q + 2*C^2*c^2*r*q] +
+      // [A^2*ab^2*q^2 + ab^2 - 2*B*ab^2*q + B^2*ab^2*q^2 + C^2*c^2*q^2]  =  0
+
+      //System.err.println("    computing Y bound");
+      
+      // Useful subexpressions for this bound
+      final double q = B*abSquared*k;
+      final double qSquared = q * q;
+
+      // Quadratic equation
+      final double a = ASquared*abSquared*rSquared + BSquared*abSquared*rSquared + CSquared*cSquared*rSquared - 4.0;
+      final double b = 2.0*ASquared*abSquared*r*q - 2.0*B*abSquared*r + 2.0*BSquared*abSquared*r*q + 2.0*CSquared*cSquared*r*q;
+      final double c = ASquared*abSquared*qSquared + abSquared - 2.0*B*abSquared*q + BSquared*abSquared*qSquared + CSquared*cSquared*qSquared;
+
+      if (Math.abs(a) >= MINIMUM_RESOLUTION_SQUARED) {
+        final double sqrtTerm = b*b - 4.0*a*c;
+        if (Math.abs(sqrtTerm) < MINIMUM_RESOLUTION_SQUARED) {
+          // One solution
+          final double m = -b / (2.0 * a);
+          final double l = r * m + q;
+          // x = (-l*A * ab^2 ) / (2 * m)
+          // y = ((1.0-l*B) * ab^2) / ( 2 * m)
+          // z = (-l*C * c^2)/ (2 * m)
+          final double denom0 = 0.5 / m;
+          final GeoPoint thePoint = new GeoPoint(-l*A * abSquared * denom0, (1.0-l*B) * abSquared * denom0, -l*C * cSquared * denom0);
+          //Math is not quite accurate enough for this
+          //assert planetModel.pointOnSurface(thePoint): "Point: "+thePoint+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
+          //  (thePoint1.x*thePoint.x*planetModel.inverseAb*planetModel.inverseAb + thePoint.y*thePoint.y*planetModel.inverseAb*planetModel.inverseAb + thePoint.z*thePoint.z*planetModel.inverseC*planetModel.inverseC);
+          //assert evaluateIsZero(thePoint): "Evaluation of point: "+evaluate(thePoint);
+          addPoint(boundsInfo, bounds, thePoint);
+        } else if (sqrtTerm > 0.0) {
+          // Two solutions
+          final double sqrtResult = Math.sqrt(sqrtTerm);
+          final double commonDenom = 0.5/a;
+          final double m1 = (-b + sqrtResult) * commonDenom;
+          assert Math.abs(a * m1 * m1 + b * m1 + c) < MINIMUM_RESOLUTION;
+          final double m2 = (-b - sqrtResult) * commonDenom;
+          assert Math.abs(a * m2 * m2 + b * m2 + c) < MINIMUM_RESOLUTION;
+          final double l1 = r * m1 + q;
+          final double l2 = r * m2 + q;
+          // x = (-l*A * ab^2 ) / (2 * m)
+          // y = ((1.0-l*B) * ab^2) / ( 2 * m)
+          // z = (-l*C * c^2)/ (2 * m)
+          final double denom1 = 0.5 / m1;
+          final double denom2 = 0.5 / m2;
+          final GeoPoint thePoint1 = new GeoPoint(-l1*A * abSquared * denom1, (1.0-l1*B) * abSquared * denom1, -l1*C * cSquared * denom1);
+          final GeoPoint thePoint2 = new GeoPoint(-l2*A * abSquared * denom2, (1.0-l2*B) * abSquared * denom2, -l2*C * cSquared * denom2);
+          //Math is not quite accurate enough for this
+          //assert planetModel.pointOnSurface(thePoint1): "Point1: "+thePoint1+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
+          //  (thePoint1.x*thePoint1.x*planetModel.inverseAb*planetModel.inverseAb + thePoint1.y*thePoint1.y*planetModel.inverseAb*planetModel.inverseAb + thePoint1.z*thePoint1.z*planetModel.inverseC*planetModel.inverseC);
+          //assert planetModel.pointOnSurface(thePoint2): "Point2: "+thePoint2+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
+          //  (thePoint2.x*thePoint2.x*planetModel.inverseAb*planetModel.inverseAb + thePoint2.y*thePoint2.y*planetModel.inverseAb*planetModel.inverseAb + thePoint2.z*thePoint2.z*planetModel.inverseC*planetModel.inverseC);
+          //assert evaluateIsZero(thePoint1): "Evaluation of point1: "+evaluate(thePoint1);
+          //assert evaluateIsZero(thePoint2): "Evaluation of point2: "+evaluate(thePoint2);
+          addPoint(boundsInfo, bounds, thePoint1);
+          addPoint(boundsInfo, bounds, thePoint2);
+        } else {
+          // No solutions
+        }
+      } else if (Math.abs(b) > MINIMUM_RESOLUTION_SQUARED) {
+        // a = 0, so m = - c / b
+        final double m = -c / b;
+        final double l = r * m + q;
+        // x = ( -l*A * ab^2 ) / (2 * m)
+        // y = ((1-l*B) * ab^2) / ( 2 * m)
+        // z = (-l*C * c^2)/ (2 * m)
+        final double denom0 = 0.5 / m;
+        final GeoPoint thePoint = new GeoPoint(-l*A * abSquared * denom0, (1.0-l*B) * abSquared * denom0, -l*C * cSquared * denom0);
+        //Math is not quite accurate enough for this
+        //assert planetModel.pointOnSurface(thePoint): "Point: "+thePoint+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
+        //  (thePoint.x*thePoint.x*planetModel.inverseAb*planetModel.inverseAb + thePoint.y*thePoint.y*planetModel.inverseAb*planetModel.inverseAb + thePoint.z*thePoint.z*planetModel.inverseC*planetModel.inverseC);
+        //assert evaluateIsZero(thePoint): "Evaluation of point: "+evaluate(thePoint);
+        addPoint(boundsInfo, bounds, thePoint);
+      } else {
+        // Something went very wrong; a = b = 0
+      }
+    }
+  }
+  
+  /**
+   * Accumulate bounds information for this plane, intersected with the unit sphere.
+   * Updates both latitude and longitude information, using max/min points found
+   * within the specified bounds.
+   *
+   * @param planetModel is the planet model to use in determining bounds.
+   * @param boundsInfo is the lat/lon info to update with additional bounding information.
+   * @param bounds     are the surfaces delineating what's inside the shape.
+   */
+  public void recordBounds(final PlanetModel planetModel, final LatLonBounds boundsInfo, final Membership... bounds) {
+    // For clarity, load local variables with good names
+    final double A = this.x;
+    final double B = this.y;
+    final double C = this.z;
+
+    // Now compute latitude min/max points
+    if (!boundsInfo.checkNoTopLatitudeBound() || !boundsInfo.checkNoBottomLatitudeBound()) {
+      //System.err.println("Looking at latitude for plane "+this);
+      // With ellipsoids, we really have only one viable way to do this computation.
+      // Specifically, we compute an appropriate vertical plane, based on the current plane's x-y orientation, and
+      // then intersect it with this one and with the ellipsoid.  This gives us zero, one, or two points to use
+      // as bounds.
+      // There is one special case: horizontal circles.  These require TWO vertical planes: one for the x, and one for
+      // the y, and we use all four resulting points in the bounds computation.
+      if ((Math.abs(A) >= MINIMUM_RESOLUTION || Math.abs(B) >= MINIMUM_RESOLUTION)) {
+        // NOT a horizontal circle!
+        //System.err.println(" Not a horizontal circle");
+        final Plane verticalPlane = constructNormalizedZPlane(A,B);
+        final GeoPoint[] points = findIntersections(planetModel, verticalPlane, bounds, NO_BOUNDS);
+        for (final GeoPoint point : points) {
+          addPoint(boundsInfo, bounds, point);
+        }
+      } else {
+        // Horizontal circle.  Since a==b, any vertical plane suffices.
+        final GeoPoint[] points = findIntersections(planetModel, normalXPlane, NO_BOUNDS, NO_BOUNDS);
+        boundsInfo.addZValue(points[0]);
+      }
+      //System.err.println("Done latitude bounds");
+    }
+
+    // First, figure out our longitude bounds, unless we no longer need to consider that
+    if (!boundsInfo.checkNoLongitudeBound()) {
+      //System.err.println("Computing longitude bounds for "+this);
+      //System.out.println("A = "+A+" B = "+B+" C = "+C+" D = "+D);
+      // Compute longitude bounds
+
+      double a;
+      double b;
+      double c;
+
+      if (Math.abs(C) < MINIMUM_RESOLUTION) {
+        // Degenerate; the equation describes a line
+        //System.out.println("It's a zero-width ellipse");
+        // Ax + By + D = 0
+        if (Math.abs(D) >= MINIMUM_RESOLUTION) {
+          if (Math.abs(A) > Math.abs(B)) {
+            // Use equation suitable for A != 0
+            // We need to find the endpoints of the zero-width ellipse.
+            // Geometrically, we have a line segment in x-y space.  We need to locate the endpoints
+            // of that line.  But luckily, we know some things: specifically, since it is a
+            // degenerate situation in projection, the C value had to have been 0.  That
+            // means that our line's endpoints will coincide with the projected ellipse.  All we
+            // need to do then is to find the intersection of the projected ellipse and the line
+            // equation:
+            //
+            // A x + B y + D = 0
+            //
+            // Since A != 0:
+            // x = (-By - D)/A
+            //
+            // The projected ellipse:
+            // x^2/a^2 + y^2/b^2 - 1 = 0
+            // Substitute:
+            // [(-By-D)/A]^2/a^2 + y^2/b^2 -1 = 0
+            // Multiply through by A^2:
+            // [-By - D]^2/a^2 + A^2*y^2/b^2 - A^2 = 0
+            // Multiply out:
+            // B^2*y^2/a^2 + 2BDy/a^2 + D^2/a^2 + A^2*y^2/b^2 - A^2 = 0
+            // Group:
+            // y^2 * [B^2/a^2 + A^2/b^2] + y [2BD/a^2] + [D^2/a^2-A^2] = 0
+
+            a = B * B * planetModel.inverseAbSquared + A * A * planetModel.inverseAbSquared;
+            b = 2.0 * B * D * planetModel.inverseAbSquared;
+            c = D * D * planetModel.inverseAbSquared - A * A;
+
+            double sqrtClause = b * b - 4.0 * a * c;
+
+            if (Math.abs(sqrtClause) < MINIMUM_RESOLUTION_SQUARED) {
+              double y0 = -b / (2.0 * a);
+              double x0 = (-D - B * y0) / A;
+              double z0 = 0.0;
+              addPoint(boundsInfo, bounds, new GeoPoint(x0, y0, z0));
+            } else if (sqrtClause > 0.0) {
+              double sqrtResult = Math.sqrt(sqrtClause);
+              double denom = 1.0 / (2.0 * a);
+              double Hdenom = 1.0 / A;
+
+              double y0a = (-b + sqrtResult) * denom;
+              double y0b = (-b - sqrtResult) * denom;
+
+              double x0a = (-D - B * y0a) * Hdenom;
+              double x0b = (-D - B * y0b) * Hdenom;
+
+              double z0a = 0.0;
+              double z0b = 0.0;
+
+              addPoint(boundsInfo, bounds, new GeoPoint(x0a, y0a, z0a));
+              addPoint(boundsInfo, bounds, new GeoPoint(x0b, y0b, z0b));
+            }
+
+          } else {
+            // Use equation suitable for B != 0
+            // Since I != 0, we rewrite:
+            // y = (-Ax - D)/B
+            a = B * B * planetModel.inverseAbSquared + A * A * planetModel.inverseAbSquared;
+            b = 2.0 * A * D * planetModel.inverseAbSquared;
+            c = D * D * planetModel.inverseAbSquared - B * B;
+
+            double sqrtClause = b * b - 4.0 * a * c;
+
+            if (Math.abs(sqrtClause) < MINIMUM_RESOLUTION_SQUARED) {
+              double x0 = -b / (2.0 * a);
+              double y0 = (-D - A * x0) / B;
+              double z0 = 0.0;
+              addPoint(boundsInfo, bounds, new GeoPoint(x0, y0, z0));
+            } else if (sqrtClause > 0.0) {
+              double sqrtResult = Math.sqrt(sqrtClause);
+              double denom = 1.0 / (2.0 * a);
+              double Idenom = 1.0 / B;
+
+              double x0a = (-b + sqrtResult) * denom;
+              double x0b = (-b - sqrtResult) * denom;
+              double y0a = (-D - A * x0a) * Idenom;
+              double y0b = (-D - A * x0b) * Idenom;
+              double z0a = 0.0;
+              double z0b = 0.0;
+
+              addPoint(boundsInfo, bounds, new GeoPoint(x0a, y0a, z0a));
+              addPoint(boundsInfo, bounds, new GeoPoint(x0b, y0b, z0b));
+            }
+          }
+        }
+
+      } else {
+        //System.err.println("General longitude bounds...");
+
+        // NOTE WELL: The x,y,z values generated here are NOT on the unit sphere.
+        // They are for lat/lon calculation purposes only.  x-y is meant to be used for longitude determination,
+        // and z for latitude, and that's all the values are good for.
+
+        // (1) Intersect the plane and the ellipsoid, and project the results into the x-y plane:
+        // From plane:
+        // z = (-Ax - By - D) / C
+        // From ellipsoid:
+        // x^2/a^2 + y^2/b^2 + [(-Ax - By - D) / C]^2/c^2 = 1
+        // Simplify/expand:
+        // C^2*x^2/a^2 + C^2*y^2/b^2 + (-Ax - By - D)^2/c^2 = C^2
+        //
+        // x^2 * C^2/a^2 + y^2 * C^2/b^2 + x^2 * A^2/c^2 + ABxy/c^2 + ADx/c^2 + ABxy/c^2 + y^2 * B^2/c^2 + BDy/c^2 + ADx/c^2 + BDy/c^2 + D^2/c^2 = C^2
+        // Group:
+        // [A^2/c^2 + C^2/a^2] x^2 + [B^2/c^2 + C^2/b^2] y^2 + [2AB/c^2]xy + [2AD/c^2]x + [2BD/c^2]y + [D^2/c^2-C^2] = 0
+        // For convenience, introduce post-projection coefficient variables to make life easier.
+        // E x^2 + F y^2 + G xy + H x + I y + J = 0
+        double E = A * A * planetModel.inverseCSquared + C * C * planetModel.inverseAbSquared;
+        double F = B * B * planetModel.inverseCSquared + C * C * planetModel.inverseAbSquared;
+        double G = 2.0 * A * B * planetModel.inverseCSquared;
+        double H = 2.0 * A * D * planetModel.inverseCSquared;
+        double I = 2.0 * B * D * planetModel.inverseCSquared;
+        double J = D * D * planetModel.inverseCSquared - C * C;
+
+        //System.err.println("E = " + E + " F = " + F + " G = " + G + " H = "+ H + " I = " + I + " J = " + J);
+
+        // Check if the origin is within, by substituting x = 0, y = 0 and seeing if less than zero
+        if (Math.abs(J) >= MINIMUM_RESOLUTION && J > 0.0) {
+          // The derivative of the curve above is:
+          // 2Exdx + 2Fydy + G(xdy+ydx) + Hdx + Idy = 0
+          // (2Ex + Gy + H)dx + (2Fy + Gx + I)dy = 0
+          // dy/dx = - (2Ex + Gy + H) / (2Fy + Gx + I)
+          //
+          // The equation of a line going through the origin with the slope dy/dx is:
+          // y = dy/dx x
+          // y = - (2Ex + Gy + H) / (2Fy + Gx + I)  x
+          // Rearrange:
+          // (2Fy + Gx + I) y + (2Ex + Gy + H) x = 0
+          // 2Fy^2 + Gxy + Iy + 2Ex^2 + Gxy + Hx = 0
+          // 2Ex^2 + 2Fy^2 + 2Gxy + Hx + Iy = 0
+          //
+          // Multiply the original equation by 2:
+          // 2E x^2 + 2F y^2 + 2G xy + 2H x + 2I y + 2J = 0
+          // Subtract one from the other, to remove the high-order terms:
+          // Hx + Iy + 2J = 0
+          // Now, we can substitute either x = or y = into the derivative equation, or into the original equation.
+          // But we will need to base this on which coefficient is non-zero
+
+          if (Math.abs(H) > Math.abs(I)) {
+            //System.err.println(" Using the y quadratic");
+            // x = (-2J - Iy)/H
+
+            // Plug into the original equation:
+            // E [(-2J - Iy)/H]^2 + F y^2 + G [(-2J - Iy)/H]y + H [(-2J - Iy)/H] + I y + J = 0
+            // E [(-2J - Iy)/H]^2 + F y^2 + G [(-2J - Iy)/H]y - J = 0
+            // Same equation as derivative equation, except for a factor of 2!  So it doesn't matter which we pick.
+
+            // Plug into derivative equation:
+            // 2E[(-2J - Iy)/H]^2 + 2Fy^2 + 2G[(-2J - Iy)/H]y + H[(-2J - Iy)/H] + Iy = 0
+            // 2E[(-2J - Iy)/H]^2 + 2Fy^2 + 2G[(-2J - Iy)/H]y - 2J = 0
+            // E[(-2J - Iy)/H]^2 + Fy^2 + G[(-2J - Iy)/H]y - J = 0
+
+            // Multiply by H^2 to make manipulation easier
+            // E[(-2J - Iy)]^2 + F*H^2*y^2 + GH[(-2J - Iy)]y - J*H^2 = 0
+            // Do the square
+            // E[4J^2 + 4IJy + I^2*y^2] + F*H^2*y^2 + GH(-2Jy - I*y^2) - J*H^2 = 0
+
+            // Multiply it out
+            // 4E*J^2 + 4EIJy + E*I^2*y^2 + H^2*Fy^2 - 2GHJy - GH*I*y^2 - J*H^2 = 0
+            // Group:
+            // y^2 [E*I^2 - GH*I + F*H^2] + y [4EIJ - 2GHJ] + [4E*J^2 - J*H^2] = 0
+
+            a = E * I * I - G * H * I + F * H * H;
+            b = 4.0 * E * I * J - 2.0 * G * H * J;
+            c = 4.0 * E * J * J - J * H * H;
+
+            //System.out.println("a="+a+" b="+b+" c="+c);
+            double sqrtClause = b * b - 4.0 * a * c;
+            //System.out.println("sqrtClause="+sqrtClause);
+
+            if (Math.abs(sqrtClause) < MINIMUM_RESOLUTION_CUBED) {
+              //System.err.println(" One solution");
+              double y0 = -b / (2.0 * a);
+              double x0 = (-2.0 * J - I * y0) / H;
+              double z0 = (-A * x0 - B * y0 - D) / C;
+
+              addPoint(boundsInfo, bounds, new GeoPoint(x0, y0, z0));
+            } else if (sqrtClause > 0.0) {
+              //System.err.println(" Two solutions");
+              double sqrtResult = Math.sqrt(sqrtClause);
+              double denom = 1.0 / (2.0 * a);
+              double Hdenom = 1.0 / H;
+              double Cdenom = 1.0 / C;
+
+              double y0a = (-b + sqrtResult) * denom;
+              double y0b = (-b - sqrtResult) * denom;
+              double x0a = (-2.0 * J - I * y0a) * Hdenom;
+              double x0b = (-2.0 * J - I * y0b) * Hdenom;
+              double z0a = (-A * x0a - B * y0a - D) * Cdenom;
+              double z0b = (-A * x0b - B * y0b - D) * Cdenom;
+
+              addPoint(boundsInfo, bounds, new GeoPoint(x0a, y0a, z0a));
+              addPoint(boundsInfo, bounds, new GeoPoint(x0b, y0b, z0b));
+            }
+
+          } else {
+            //System.err.println(" Using the x quadratic");
+            // y = (-2J - Hx)/I
+
+            // Plug into the original equation:
+            // E x^2 + F [(-2J - Hx)/I]^2 + G x[(-2J - Hx)/I] - J = 0
+
+            // Multiply by I^2 to make manipulation easier
+            // E * I^2 * x^2 + F [(-2J - Hx)]^2 + GIx[(-2J - Hx)] - J * I^2 = 0
+            // Do the square
+            // E * I^2 * x^2 + F [ 4J^2 + 4JHx + H^2*x^2] + GI[(-2Jx - H*x^2)] - J * I^2 = 0
+
+            // Multiply it out
+            // E * I^2 * x^2 + 4FJ^2 + 4FJHx + F*H^2*x^2 - 2GIJx - HGI*x^2 - J * I^2 = 0
+            // Group:
+            // x^2 [E*I^2 - GHI + F*H^2] + x [4FJH - 2GIJ] + [4FJ^2 - J*I^2] = 0
+
+            // E x^2 + F y^2 + G xy + H x + I y + J = 0
+
+            a = E * I * I - G * H * I + F * H * H;
+            b = 4.0 * F * H * J - 2.0 * G * I * J;
+            c = 4.0 * F * J * J - J * I * I;
+
+            //System.out.println("a="+a+" b="+b+" c="+c);
+            double sqrtClause = b * b - 4.0 * a * c;
+            //System.out.println("sqrtClause="+sqrtClause);
+            if (Math.abs(sqrtClause) < MINIMUM_RESOLUTION_CUBED) {
+              //System.err.println(" One solution; sqrt clause was "+sqrtClause);
+              double x0 = -b / (2.0 * a);
+              double y0 = (-2.0 * J - H * x0) / I;
+              double z0 = (-A * x0 - B * y0 - D) / C;
+              // Verify that x&y fulfill the equation
+              // 2Ex^2 + 2Fy^2 + 2Gxy + Hx + Iy = 0
+              addPoint(boundsInfo, bounds, new GeoPoint(x0, y0, z0));
+            } else if (sqrtClause > 0.0) {
+              //System.err.println(" Two solutions");
+              double sqrtResult = Math.sqrt(sqrtClause);
+              double denom = 1.0 / (2.0 * a);
+              double Idenom = 1.0 / I;
+              double Cdenom = 1.0 / C;
+
+              double x0a = (-b + sqrtResult) * denom;
+              double x0b = (-b - sqrtResult) * denom;
+              double y0a = (-2.0 * J - H * x0a) * Idenom;
+              double y0b = (-2.0 * J - H * x0b) * Idenom;
+              double z0a = (-A * x0a - B * y0a - D) * Cdenom;
+              double z0b = (-A * x0b - B * y0b - D) * Cdenom;
+
+              addPoint(boundsInfo, bounds, new GeoPoint(x0a, y0a, z0a));
+              addPoint(boundsInfo, bounds, new GeoPoint(x0b, y0b, z0b));
+            }
+          }
+        }
+      }
+    }
+
+  }
+
+  /** Add a point to boundsInfo if within a specifically bounded area.
+   * @param boundsInfo is the object to be modified.
+   * @param bounds is the area that the point must be within.
+   * @param point is the point.
+   */
+  protected static void addPoint(final Bounds boundsInfo, final Membership[] bounds, final GeoPoint point) {
+    // Make sure the discovered point is within the bounds
+    for (Membership bound : bounds) {
+      if (!bound.isWithin(point))
+        return;
+    }
+    // Add the point
+    boundsInfo.addPoint(point);
+  }
+
+  /** Add a point to boundsInfo if within a specifically bounded area.
+   * @param boundsInfo is the object to be modified.
+   * @param bounds is the area that the point must be within.
+   * @param x is the x value.
+   * @param y is the y value.
+   * @param z is the z value.
+   */
+  /*
+  protected static void addPoint(final Bounds boundsInfo, final Membership[] bounds, final double x, final double y, final double z) {
+    //System.err.println(" Want to add point x="+x+" y="+y+" z="+z);
+    // Make sure the discovered point is within the bounds
+    for (Membership bound : bounds) {
+      if (!bound.isWithin(x, y, z))
+        return;
+    }
+    // Add the point
+    //System.err.println("  point added");
+    //System.out.println("Adding point x="+x+" y="+y+" z="+z);
+    boundsInfo.addPoint(x, y, z);
+  }
+  */
+
+  /**
+   * Determine whether the plane intersects another plane within the
+   * bounds provided.
+   *
+   * @param planetModel is the planet model to use in determining intersection.
+   * @param q                 is the other plane.
+   * @param notablePoints     are points to look at to disambiguate cases when the two planes are identical.
+   * @param moreNotablePoints are additional points to look at to disambiguate cases when the two planes are identical.
+   * @param bounds            is one part of the bounds.
+   * @param moreBounds        are more bounds.
+   * @return true if there's an intersection.
+   */
+  public boolean intersects(final PlanetModel planetModel, final Plane q, final GeoPoint[] notablePoints, final GeoPoint[] moreNotablePoints, final Membership[] bounds, final Membership... moreBounds) {
+    //System.err.println("Does plane "+this+" intersect with plane "+q);
+    // If the two planes are identical, then the math will find no points of intersection.
+    // So a special case of this is to check for plane equality.  But that is not enough, because
+    // what we really need at that point is to determine whether overlap occurs between the two parts of the intersection
+    // of plane and circle.  That is, are there *any* points on the plane that are within the bounds described?
+    if (isNumericallyIdentical(q)) {
+      //System.err.println(" Identical plane");
+      // The only way to efficiently figure this out will be to have a list of trial points available to evaluate.
+      // We look for any point that fulfills all the bounds.
+      for (GeoPoint p : notablePoints) {
+        if (meetsAllBounds(p, bounds, moreBounds)) {
+          //System.err.println("  found a notable point in bounds, so intersects");
+          return true;
+        }
+      }
+      for (GeoPoint p : moreNotablePoints) {
+        if (meetsAllBounds(p, bounds, moreBounds)) {
+          //System.err.println("  found a notable point in bounds, so intersects");
+          return true;
+        }
+      }
+      //System.err.println("  no notable points inside found; no intersection");
+      return false;
+    }
+    return findIntersections(planetModel, q, bounds, moreBounds).length > 0;
+  }
+
+  /**
+   * Returns true if this plane and the other plane are identical within the margin of error.
+   * @param p is the plane to compare against.
+   * @return true if the planes are numerically identical.
+   */
+  protected boolean isNumericallyIdentical(final Plane p) {
+    // We can get the correlation by just doing a parallel plane check.  If that passes, then compute a point on the plane
+    // (using D) and see if it also on the other plane.
+    if (Math.abs(this.y * p.z - this.z * p.y) >= MINIMUM_RESOLUTION)
+      return false;
+    if (Math.abs(this.z * p.x - this.x * p.z) >= MINIMUM_RESOLUTION)
+      return false;
+    if (Math.abs(this.x * p.y - this.y * p.x) >= MINIMUM_RESOLUTION)
+      return false;
+
+    // Now, see whether the parallel planes are in fact on top of one another.
+    // The math:
+    // We need a single point that fulfills:
+    // Ax + By + Cz + D = 0
+    // Pick:
+    // x0 = -(A * D) / (A^2 + B^2 + C^2)
+    // y0 = -(B * D) / (A^2 + B^2 + C^2)
+    // z0 = -(C * D) / (A^2 + B^2 + C^2)
+    // Check:
+    // A (x0) + B (y0) + C (z0) + D =? 0
+    // A (-(A * D) / (A^2 + B^2 + C^2)) + B (-(B * D) / (A^2 + B^2 + C^2)) + C (-(C * D) / (A^2 + B^2 + C^2)) + D ?= 0
+    // -D [ A^2 / (A^2 + B^2 + C^2) + B^2 / (A^2 + B^2 + C^2) + C^2 / (A^2 + B^2 + C^2)] + D ?= 0
+    // Yes.
+    final double denom = 1.0 / (p.x * p.x + p.y * p.y + p.z * p.z);
+    return evaluateIsZero(-p.x * p.D * denom, -p.y * p.D * denom, -p.z * p.D * denom);
+  }
+
+  /**
+   * Check if a vector meets the provided bounds.
+   * @param p is the vector.
+   * @param bounds are the bounds.
+   * @return true if the vector describes a point within the bounds.
+   */
+  protected static boolean meetsAllBounds(final Vector p, final Membership[] bounds) {
+    return meetsAllBounds(p.x, p.y, p.z, bounds);
+  }
+
+  /**
+   * Check if a vector meets the provided bounds.
+   * @param x is the x value.
+   * @param y is the y value.
+   * @param z is the z value.
+   * @param bounds are the bounds.
+   * @return true if the vector describes a point within the bounds.
+   */
+  protected static boolean meetsAllBounds(final double x, final double y, final double z, final Membership[] bounds) {
+    for (final Membership bound : bounds) {
+      if (!bound.isWithin(x,y,z))
+        return false;
+    }
+    return true;
+  }
+
+  /**
+   * Check if a vector meets the provided bounds.
+   * @param p is the vector.
+   * @param bounds are the bounds.
+   * @param moreBounds are an additional set of bounds.
+   * @return true if the vector describes a point within the bounds.
+   */
+  protected static boolean meetsAllBounds(final Vector p, final Membership[] bounds, final Membership[] moreBounds) {
+    return meetsAllBounds(p.x, p.y, p.z, bounds, moreBounds);
+  }
+
+  /**
+   * Check if a vector meets the provided bounds.
+   * @param x is the x value.
+   * @param y is the y value.
+   * @param z is the z value.
+   * @param bounds are the bounds.
+   * @param moreBounds are an additional set of bounds.
+   * @return true if the vector describes a point within the bounds.
+   */
+  protected static boolean meetsAllBounds(final double x, final double y, final double z, final Membership[] bounds,
+                                          final Membership[] moreBounds) {
+    return meetsAllBounds(x,y,z, bounds) && meetsAllBounds(x,y,z, moreBounds);
+  }
+
+  /**
+   * Find a sample point on the intersection between two planes and the world.
+   * @param planetModel is the planet model.
+   * @param q is the second plane to consider.
+   * @return a sample point that is on the intersection between the two planes and the world.
+   */
+  public GeoPoint getSampleIntersectionPoint(final PlanetModel planetModel, final Plane q) {
+    final GeoPoint[] intersections = findIntersections(planetModel, q, NO_BOUNDS, NO_BOUNDS);
+    if (intersections.length == 0)
+      return null;
+    return intersections[0];
+  }
+
+  @Override
+  public String toString() {
+    return "[A=" + x + ", B=" + y + "; C=" + z + "; D=" + D + "]";
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!super.equals(o))
+      return false;
+    if (!(o instanceof Plane))
+      return false;
+    Plane other = (Plane) o;
+    return other.D == D;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    long temp;
+    temp = Double.doubleToLongBits(D);
+    result = 31 * result + (int) (temp ^ (temp >>> 32));
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/PlanetModel.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/PlanetModel.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/PlanetModel.java
new file mode 100644
index 0000000..d45d776
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/PlanetModel.java
@@ -0,0 +1,277 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Holds mathematical constants associated with the model of a planet.
+ * @lucene.experimental
+ */
+public class PlanetModel {
+  
+  /** Planet model corresponding to sphere. */
+  public static final PlanetModel SPHERE = new PlanetModel(1.0,1.0);
+
+  /** Mean radius */
+  public static final double WGS84_MEAN = 6371009.0;
+  /** Polar radius */
+  public static final double WGS84_POLAR = 6356752.314245;
+  /** Equatorial radius */
+  public static final double WGS84_EQUATORIAL = 6378137.0;
+  /** Planet model corresponding to WGS84 */
+  public static final PlanetModel WGS84 = new PlanetModel(WGS84_EQUATORIAL/WGS84_MEAN,
+    WGS84_POLAR/WGS84_MEAN);
+
+  // Surface of the planet:
+  // x^2/a^2 + y^2/b^2 + z^2/c^2 = 1.0
+  // Scaling factors are a,b,c.  geo3d can only support models where a==b, so use ab instead.
+  
+  /** The x/y scaling factor */
+  public final double ab;
+  /** The z scaling factor */
+  public final double c;
+  /** The inverse of ab */
+  public final double inverseAb;
+  /** The inverse of c */
+  public final double inverseC;
+  /** The square of the inverse of ab */
+  public final double inverseAbSquared;
+  /** The square of the inverse of c */
+  public final double inverseCSquared;
+  /** The flattening value */
+  public final double flattening;
+  /** The square ratio */
+  public final double squareRatio;
+  
+  // We do NOT include radius, because all computations in geo3d are in radians, not meters.
+  
+  // Compute north and south pole for planet model, since these are commonly used.
+  
+  /** North pole */
+  public final GeoPoint NORTH_POLE;
+  /** South pole */
+  public final GeoPoint SOUTH_POLE;
+  /** Min X pole */
+  public final GeoPoint MIN_X_POLE;
+  /** Max X pole */
+  public final GeoPoint MAX_X_POLE;
+  /** Min Y pole */
+  public final GeoPoint MIN_Y_POLE;
+  /** Max Y pole */
+  public final GeoPoint MAX_Y_POLE;
+  
+  /** Constructor.
+   * @param ab is the x/y scaling factor.
+   * @param c is the z scaling factor.
+   */
+  public PlanetModel(final double ab, final double c) {
+    this.ab = ab;
+    this.c = c;
+    this.inverseAb = 1.0 / ab;
+    this.inverseC = 1.0 / c;
+    this.flattening = (ab - c) * inverseAb;
+    this.squareRatio = (ab * ab - c * c) / (c * c);
+    this.inverseAbSquared = inverseAb * inverseAb;
+    this.inverseCSquared = inverseC * inverseC;
+    this.NORTH_POLE = new GeoPoint(c, 0.0, 0.0, 1.0, Math.PI * 0.5, 0.0);
+    this.SOUTH_POLE = new GeoPoint(c, 0.0, 0.0, -1.0, -Math.PI * 0.5, 0.0);
+    this.MIN_X_POLE = new GeoPoint(ab, -1.0, 0.0, 0.0, 0.0, -Math.PI);
+    this.MAX_X_POLE = new GeoPoint(ab, 1.0, 0.0, 0.0, 0.0, 0.0);
+    this.MIN_Y_POLE = new GeoPoint(ab, 0.0, -1.0, 0.0, 0.0, -Math.PI * 0.5);
+    this.MAX_Y_POLE = new GeoPoint(ab, 0.0, 1.0, 0.0, 0.0, Math.PI * 0.5);
+  }
+  
+  /** Find the minimum magnitude of all points on the ellipsoid.
+   * @return the minimum magnitude for the planet.
+   */
+  public double getMinimumMagnitude() {
+    return Math.min(this.ab, this.c);
+  }
+
+  /** Find the maximum magnitude of all points on the ellipsoid.
+   * @return the maximum magnitude for the planet.
+   */
+  public double getMaximumMagnitude() {
+    return Math.max(this.ab, this.c);
+  }
+  
+  /** Find the minimum x value.
+   *@return the minimum X value.
+   */
+  public double getMinimumXValue() {
+    return -this.ab;
+  }
+  
+  /** Find the maximum x value.
+   *@return the maximum X value.
+   */
+  public double getMaximumXValue() {
+    return this.ab;
+  }
+
+  /** Find the minimum y value.
+   *@return the minimum Y value.
+   */
+  public double getMinimumYValue() {
+    return -this.ab;
+  }
+  
+  /** Find the maximum y value.
+   *@return the maximum Y value.
+   */
+  public double getMaximumYValue() {
+    return this.ab;
+  }
+  
+  /** Find the minimum z value.
+   *@return the minimum Z value.
+   */
+  public double getMinimumZValue() {
+    return -this.c;
+  }
+  
+  /** Find the maximum z value.
+   *@return the maximum Z value.
+   */
+  public double getMaximumZValue() {
+    return this.c;
+  }
+
+  /** Check if point is on surface.
+   * @param v is the point to check.
+   * @return true if the point is on the planet surface.
+   */
+  public boolean pointOnSurface(final Vector v) {
+    return pointOnSurface(v.x, v.y, v.z);
+  }
+  
+  /** Check if point is on surface.
+   * @param x is the x coord.
+   * @param y is the y coord.
+   * @param z is the z coord.
+   */
+  public boolean pointOnSurface(final double x, final double y, final double z) {
+    // Equation of planet surface is:
+    // x^2 / a^2 + y^2 / b^2 + z^2 / c^2 - 1 = 0
+    return Math.abs(x * x * inverseAb * inverseAb + y * y * inverseAb * inverseAb + z * z * inverseC * inverseC - 1.0) < Vector.MINIMUM_RESOLUTION;
+  }
+
+  /** Check if point is outside surface.
+   * @param v is the point to check.
+   * @return true if the point is outside the planet surface.
+   */
+  public boolean pointOutside(final Vector v) {
+    return pointOutside(v.x, v.y, v.z);
+  }
+  
+  /** Check if point is outside surface.
+   * @param x is the x coord.
+   * @param y is the y coord.
+   * @param z is the z coord.
+   */
+  public boolean pointOutside(final double x, final double y, final double z) {
+    // Equation of planet surface is:
+    // x^2 / a^2 + y^2 / b^2 + z^2 / c^2 - 1 = 0
+    return (x * x + y * y) * inverseAb * inverseAb + z * z * inverseC * inverseC - 1.0 > Vector.MINIMUM_RESOLUTION;
+  }
+  
+  /** Compute surface distance between two points.
+   * @param p1 is the first point.
+   * @param p2 is the second point.
+   * @return the adjusted angle, when multiplied by the mean earth radius, yields a surface distance.  This will differ
+   * from GeoPoint.arcDistance() only when the planet model is not a sphere. @see {@link GeoPoint#arcDistance(GeoPoint)}
+   */
+  public double surfaceDistance(final GeoPoint p1, final GeoPoint p2) {
+    final double latA = p1.getLatitude();
+    final double lonA = p1.getLongitude();
+    final double latB = p2.getLatitude();
+    final double lonB = p2.getLongitude();
+
+    final double L = lonB - lonA;
+    final double oF = 1.0 - this.flattening;
+    final double U1 = Math.atan(oF * Math.tan(latA));
+    final double U2 = Math.atan(oF * Math.tan(latB));
+    final double sU1 = Math.sin(U1);
+    final double cU1 = Math.cos(U1);
+    final double sU2 = Math.sin(U2);
+    final double cU2 = Math.cos(U2);
+
+    double sigma, sinSigma, cosSigma;
+    double cos2Alpha, cos2SigmaM;
+    
+    double lambda = L;
+    double iters = 100;
+
+    do {
+      final double sinLambda = Math.sin(lambda);
+      final double cosLambda = Math.cos(lambda);
+      sinSigma = Math.sqrt((cU2 * sinLambda) * (cU2 * sinLambda) + (cU1 * sU2 - sU1 * cU2 * cosLambda)
+          * (cU1 * sU2 - sU1 * cU2 * cosLambda));
+      if (Math.abs(sinSigma) < Vector.MINIMUM_RESOLUTION)
+        return 0.0;
+
+      cosSigma = sU1 * sU2 + cU1 * cU2 * cosLambda;
+      sigma = Math.atan2(sinSigma, cosSigma);
+      final double sinAlpha = cU1 * cU2 * sinLambda / sinSigma;
+      cos2Alpha = 1.0 - sinAlpha * sinAlpha;
+      cos2SigmaM = cosSigma - 2.0 * sU1 * sU2 / cos2Alpha;
+
+      final double c = this.flattening * 0.625 * cos2Alpha * (4.0 + this.flattening * (4.0 - 3.0 * cos2Alpha));
+      final double lambdaP = lambda;
+      lambda = L + (1.0 - c) * this.flattening * sinAlpha * (sigma + c * sinSigma * (cos2SigmaM + c * cosSigma *
+          (-1.0 + 2.0 * cos2SigmaM * cos2SigmaM)));
+      if (Math.abs(lambda - lambdaP) < Vector.MINIMUM_RESOLUTION)
+        break;
+    } while (--iters > 0);
+
+    if (iters == 0)
+      return 0.0;
+
+    final double uSq = cos2Alpha * this.squareRatio;
+    final double A = 1.0 + uSq * 0.00006103515625 * (4096.0 + uSq * (-768.0 + uSq * (320.0 - 175.0 * uSq)));
+    final double B = uSq * 0.0009765625 * (256.0 + uSq * (-128.0 + uSq * (74.0 - 47.0 * uSq)));
+    final double deltaSigma = B * sinSigma * (cos2SigmaM + B * 0.25 * (cosSigma * (-1.0 + 2.0 * cos2SigmaM * cos2SigmaM) - B * 0.16666666666666666666667 * cos2SigmaM
+            * (-3.0 + 4.0 * sinSigma * sinSigma) * (-3.0 + 4.0 * cos2SigmaM * cos2SigmaM)));
+
+    return this.c * A * (sigma - deltaSigma);
+  }
+
+  @Override
+  public boolean equals(final Object o) {
+    if (!(o instanceof PlanetModel))
+      return false;
+    final PlanetModel other = (PlanetModel)o;
+    return ab == other.ab && c == other.c;
+  }
+  
+  @Override
+  public int hashCode() {
+    return Double.hashCode(ab) + Double.hashCode(c);
+  }
+  
+  @Override
+  public String toString() {
+    if (this.equals(SPHERE)) {
+      return "PlanetModel.SPHERE";
+    } else if (this.equals(WGS84)) {
+      return "PlanetModel.WGS84";
+    } else {
+      return "PlanetModel(ab="+ab+" c="+c+")";
+    }
+  }
+}
+
+


[25/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 3a31a8c)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBBoxFactory.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBBoxFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBBoxFactory.java
new file mode 100755
index 0000000..de7493e
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBBoxFactory.java
@@ -0,0 +1,111 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Factory for {@link GeoBBox}.
+ *
+ * @lucene.experimental
+ */
+public class GeoBBoxFactory {
+  private GeoBBoxFactory() {
+  }
+
+  /**
+   * Create a geobbox of the right kind given the specified bounds.
+   *
+   * @param planetModel is the planet model
+   * @param topLat    is the top latitude
+   * @param bottomLat is the bottom latitude
+   * @param leftLon   is the left longitude
+   * @param rightLon  is the right longitude
+   * @return a GeoBBox corresponding to what was specified.
+   */
+  public static GeoBBox makeGeoBBox(final PlanetModel planetModel, double topLat, double bottomLat, double leftLon, double rightLon) {
+    //System.err.println("Making rectangle for topLat="+topLat*180.0/Math.PI+", bottomLat="+bottomLat*180.0/Math.PI+", leftLon="+leftLon*180.0/Math.PI+", rightlon="+rightLon*180.0/Math.PI);
+    if (topLat > Math.PI * 0.5)
+      topLat = Math.PI * 0.5;
+    if (bottomLat < -Math.PI * 0.5)
+      bottomLat = -Math.PI * 0.5;
+    if (leftLon < -Math.PI)
+      leftLon = -Math.PI;
+    if (rightLon > Math.PI)
+      rightLon = Math.PI;
+    if (Math.abs(leftLon + Math.PI) < Vector.MINIMUM_RESOLUTION && Math.abs(rightLon - Math.PI) < Vector.MINIMUM_RESOLUTION) {
+      if (Math.abs(topLat - Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION && Math.abs(bottomLat + Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION)
+        return new GeoWorld(planetModel);
+      if (Math.abs(topLat - bottomLat) < Vector.MINIMUM_RESOLUTION) {
+        if (Math.abs(topLat - Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION || Math.abs(topLat + Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION)
+          return new GeoDegeneratePoint(planetModel, topLat, 0.0);
+        return new GeoDegenerateLatitudeZone(planetModel, topLat);
+      }
+      if (Math.abs(topLat - Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION)
+        return new GeoNorthLatitudeZone(planetModel, bottomLat);
+      else if (Math.abs(bottomLat + Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION)
+        return new GeoSouthLatitudeZone(planetModel, topLat);
+      return new GeoLatitudeZone(planetModel, topLat, bottomLat);
+    }
+    //System.err.println(" not latitude zone");
+    double extent = rightLon - leftLon;
+    if (extent < 0.0)
+      extent += Math.PI * 2.0;
+    if (topLat == Math.PI * 0.5 && bottomLat == -Math.PI * 0.5) {
+      if (Math.abs(leftLon - rightLon) < Vector.MINIMUM_RESOLUTION)
+        return new GeoDegenerateLongitudeSlice(planetModel, leftLon);
+
+      if (extent >= Math.PI)
+        return new GeoWideLongitudeSlice(planetModel, leftLon, rightLon);
+
+      return new GeoLongitudeSlice(planetModel, leftLon, rightLon);
+    }
+    //System.err.println(" not longitude slice");
+    if (Math.abs(leftLon - rightLon) < Vector.MINIMUM_RESOLUTION) {
+      if (Math.abs(topLat - bottomLat) < Vector.MINIMUM_RESOLUTION)
+        return new GeoDegeneratePoint(planetModel, topLat, leftLon);
+      return new GeoDegenerateVerticalLine(planetModel, topLat, bottomLat, leftLon);
+    }
+    //System.err.println(" not vertical line");
+    if (extent >= Math.PI) {
+      if (Math.abs(topLat - bottomLat) < Vector.MINIMUM_RESOLUTION) {
+        //System.err.println(" wide degenerate line");
+        return new GeoWideDegenerateHorizontalLine(planetModel, topLat, leftLon, rightLon);
+      }
+      if (Math.abs(topLat - Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION) {
+        return new GeoWideNorthRectangle(planetModel, bottomLat, leftLon, rightLon);
+      } else if (Math.abs(bottomLat + Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION) {
+        return new GeoWideSouthRectangle(planetModel, topLat, leftLon, rightLon);
+      }
+      //System.err.println(" wide rect");
+      return new GeoWideRectangle(planetModel, topLat, bottomLat, leftLon, rightLon);
+    }
+    if (Math.abs(topLat - bottomLat) < Vector.MINIMUM_RESOLUTION) {
+      if (Math.abs(topLat - Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION || Math.abs(topLat + Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION) {
+        return new GeoDegeneratePoint(planetModel, topLat, 0.0);
+      }
+      //System.err.println(" horizontal line");
+      return new GeoDegenerateHorizontalLine(planetModel, topLat, leftLon, rightLon);
+    }
+    if (Math.abs(topLat - Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION) {
+      return new GeoNorthRectangle(planetModel, bottomLat, leftLon, rightLon);
+    } else if (Math.abs(bottomLat + Math.PI * 0.5) <  Vector.MINIMUM_RESOLUTION) {
+      return new GeoSouthRectangle(planetModel, topLat, leftLon, rightLon);
+    }
+    //System.err.println(" rectangle");
+    return new GeoRectangle(planetModel, topLat, bottomLat, leftLon, rightLon);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseBBox.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseBBox.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseBBox.java
new file mode 100644
index 0000000..7190cdc
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseBBox.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.spatial3d.geom;
+
+/**
+ * All bounding box shapes can derive from this base class, which furnishes
+ * some common code
+ *
+ * @lucene.internal
+ */
+public abstract class GeoBaseBBox extends GeoBaseMembershipShape implements GeoBBox {
+
+  /** Construct, given planet model.
+   *@param planetModel is the planet model.
+   */
+  public GeoBaseBBox(final PlanetModel planetModel) {
+    super(planetModel);
+  }
+
+  // Signals for relationship of edge points to shape
+  
+  /** All edgepoints inside shape */
+  protected final static int ALL_INSIDE = 0;
+  /** Some edgepoints inside shape */
+  protected final static int SOME_INSIDE = 1;
+  /** No edgepoints inside shape */
+  protected final static int NONE_INSIDE = 2;
+
+  /** Determine the relationship between this BBox and the provided
+   * shape's edgepoints.
+   *@param path is the shape.
+   *@return the relationship.
+   */
+  protected int isShapeInsideBBox(final GeoShape path) {
+    final GeoPoint[] pathPoints = path.getEdgePoints();
+    boolean foundOutside = false;
+    boolean foundInside = false;
+    for (GeoPoint p : pathPoints) {
+      if (isWithin(p)) {
+        foundInside = true;
+      } else {
+        foundOutside = true;
+      }
+      if (foundInside && foundOutside) {
+        return SOME_INSIDE;
+      }
+    }
+    if (!foundInside && !foundOutside)
+      return NONE_INSIDE;
+    if (foundInside && !foundOutside)
+      return ALL_INSIDE;
+    if (foundOutside && !foundInside)
+      return NONE_INSIDE;
+    return SOME_INSIDE;
+  }
+
+}
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseCircle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseCircle.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseCircle.java
new file mode 100644
index 0000000..75219fd
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseCircle.java
@@ -0,0 +1,34 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * GeoCircles have all the characteristics of GeoBaseDistanceShapes, plus GeoSizeable.
+ *
+ * @lucene.experimental
+ */
+public abstract class GeoBaseCircle extends GeoBaseDistanceShape implements GeoCircle {
+
+  /** Constructor.
+   *@param planetModel is the planet model to use.
+   */
+  public GeoBaseCircle(final PlanetModel planetModel) {
+    super(planetModel);
+  }
+
+}
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseDistanceShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseDistanceShape.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseDistanceShape.java
new file mode 100644
index 0000000..39dcf96
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseDistanceShape.java
@@ -0,0 +1,56 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Distance shapes have capabilities of both geohashing and distance
+ * computation (which also includes point membership determination).
+ *
+ * @lucene.experimental
+ */
+public abstract class GeoBaseDistanceShape extends GeoBaseMembershipShape implements GeoDistanceShape {
+
+  /** Constructor.
+   *@param planetModel is the planet model to use.
+   */
+  public GeoBaseDistanceShape(final PlanetModel planetModel) {
+    super(planetModel);
+  }
+
+  @Override
+  public boolean isWithin(Vector point) {
+    return isWithin(point.x, point.y, point.z);
+  }
+
+  @Override
+  public double computeDistance(final DistanceStyle distanceStyle, final GeoPoint point) {
+    return computeDistance(distanceStyle, point.x, point.y, point.z);
+  }
+
+  @Override
+  public double computeDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    if (!isWithin(x,y,z)) {
+      return Double.MAX_VALUE;
+    }
+    return distance(distanceStyle, x, y, z);
+  }
+
+  /** Called by a {@code computeDistance} method if X/Y/Z is not within this shape. */
+  protected abstract double distance(final DistanceStyle distanceStyle, final double x, final double y, final double z);
+
+}
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseMembershipShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseMembershipShape.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseMembershipShape.java
new file mode 100644
index 0000000..831a7c6
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseMembershipShape.java
@@ -0,0 +1,56 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Membership shapes have capabilities of both geohashing and membership
+ * determination.  This is a useful baseclass for them.
+ *
+ * @lucene.experimental
+ */
+public abstract class GeoBaseMembershipShape extends GeoBaseShape implements GeoMembershipShape {
+
+  /** Constructor.
+   *@param planetModel is the planet model to use.
+   */
+  public GeoBaseMembershipShape(final PlanetModel planetModel) {
+    super(planetModel);
+  }
+
+  @Override
+  public boolean isWithin(Vector point) {
+    return isWithin(point.x, point.y, point.z);
+  }
+
+  @Override
+  public double computeOutsideDistance(final DistanceStyle distanceStyle, final GeoPoint point) {
+    return computeOutsideDistance(distanceStyle, point.x, point.y, point.z);
+  }
+
+  @Override
+  public double computeOutsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    if (isWithin(x,y,z)) {
+      return 0.0;
+    }
+    return outsideDistance(distanceStyle, x,y,z);
+  }
+
+  /** Called by a {@code computeOutsideDistance} method if X/Y/Z is not within this shape. */
+  protected abstract double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z);
+
+}
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBasePolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBasePolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBasePolygon.java
new file mode 100644
index 0000000..ba221ae
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBasePolygon.java
@@ -0,0 +1,34 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * GeoBasePolygon objects are the base class of most GeoPolygon objects.
+ *
+ * @lucene.experimental
+ */
+public abstract class GeoBasePolygon extends GeoBaseMembershipShape implements GeoPolygon {
+
+  /** Constructor.
+   *@param planetModel is the planet model to use.
+   */
+  public GeoBasePolygon(final PlanetModel planetModel) {
+    super(planetModel);
+  }
+
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseShape.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseShape.java
new file mode 100644
index 0000000..54896fc
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseShape.java
@@ -0,0 +1,59 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Base extended shape object.
+ *
+ * @lucene.internal
+ */
+public abstract class GeoBaseShape extends BasePlanetObject implements GeoShape {
+
+  /** Constructor.
+   *@param planetModel is the planet model to use.
+   */
+  public GeoBaseShape(final PlanetModel planetModel) {
+    super(planetModel);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    if (isWithin(planetModel.NORTH_POLE)) {
+      bounds.noTopLatitudeBound().noLongitudeBound()
+        .addPoint(planetModel.NORTH_POLE);
+    }
+    if (isWithin(planetModel.SOUTH_POLE)) {
+      bounds.noBottomLatitudeBound().noLongitudeBound()
+        .addPoint(planetModel.SOUTH_POLE);
+    }
+    if (isWithin(planetModel.MIN_X_POLE)) {
+      bounds.addPoint(planetModel.MIN_X_POLE);
+    }
+    if (isWithin(planetModel.MAX_X_POLE)) {
+      bounds.addPoint(planetModel.MAX_X_POLE);
+    }
+    if (isWithin(planetModel.MIN_Y_POLE)) {
+      bounds.addPoint(planetModel.MIN_Y_POLE);
+    }
+    if (isWithin(planetModel.MAX_Y_POLE)) {
+      bounds.addPoint(planetModel.MAX_Y_POLE);
+    }
+  }
+
+}
+
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCircle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCircle.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCircle.java
new file mode 100755
index 0000000..b05dff6
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCircle.java
@@ -0,0 +1,25 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Interface describing circular area with a center and radius.
+ *
+ * @lucene.experimental
+ */
+public interface GeoCircle extends GeoDistanceShape, GeoSizeable {
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCircleFactory.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCircleFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCircleFactory.java
new file mode 100644
index 0000000..ee75179
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCircleFactory.java
@@ -0,0 +1,43 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Class which constructs a GeoCircle representing an arbitrary circle.
+ *
+ * @lucene.experimental
+ */
+public class GeoCircleFactory {
+  private GeoCircleFactory() {
+  }
+
+  /**
+   * Create a GeoCircle of the right kind given the specified bounds.
+   * @param planetModel is the planet model.
+   * @param latitude is the center latitude.
+   * @param longitude is the center longitude.
+   * @param radius is the radius angle.
+   * @return a GeoCircle corresponding to what was specified.
+   */
+  public static GeoCircle makeGeoCircle(final PlanetModel planetModel, final double latitude, final double longitude, final double radius) {
+    if (radius < Vector.MINIMUM_RESOLUTION) {
+      return new GeoDegeneratePoint(planetModel, latitude, longitude);
+    }
+    return new GeoStandardCircle(planetModel, latitude, longitude, radius);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCompositeMembershipShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCompositeMembershipShape.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCompositeMembershipShape.java
new file mode 100755
index 0000000..9747eda
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCompositeMembershipShape.java
@@ -0,0 +1,117 @@
+/*
+ * 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.spatial3d.geom;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * GeoComposite is a set of GeoMembershipShape's, treated as a unit.
+ *
+ * @lucene.experimental
+ */
+public class GeoCompositeMembershipShape implements GeoMembershipShape {
+  /** The list of shapes. */
+  protected final List<GeoMembershipShape> shapes = new ArrayList<GeoMembershipShape>();
+
+  /** Constructor.
+   */
+  public GeoCompositeMembershipShape() {
+  }
+
+  /**
+   * Add a shape to the composite.
+   *@param shape is the shape to add.
+   */
+  public void addShape(final GeoMembershipShape shape) {
+    shapes.add(shape);
+  }
+
+  @Override
+  public boolean isWithin(final Vector point) {
+    return isWithin(point.x, point.y, point.z);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    for (GeoMembershipShape shape : shapes) {
+      if (shape.isWithin(x, y, z))
+        return true;
+    }
+    return false;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return shapes.get(0).getEdgePoints();
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    for (GeoMembershipShape shape : shapes) {
+      if (shape.intersects(p, notablePoints, bounds))
+        return true;
+    }
+    return false;
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    for (GeoMembershipShape shape : shapes) {
+      shape.getBounds(bounds);
+    }
+  }
+
+  @Override
+  public double computeOutsideDistance(final DistanceStyle distanceStyle, final GeoPoint point) {
+    return computeOutsideDistance(distanceStyle, point.x, point.y, point.z);
+  }
+
+  @Override
+  public double computeOutsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    if (isWithin(x,y,z))
+      return 0.0;
+    double distance = Double.MAX_VALUE;
+    for (GeoMembershipShape shape : shapes) {
+      final double normalDistance = shape.computeOutsideDistance(distanceStyle, x, y, z);
+      if (normalDistance < distance) {
+        distance = normalDistance;
+      }
+    }
+    return distance;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoCompositeMembershipShape))
+      return false;
+    GeoCompositeMembershipShape other = (GeoCompositeMembershipShape) o;
+
+    return super.equals(o) && shapes.equals(other.shapes);
+  }
+
+  @Override
+  public int hashCode() {
+    return super.hashCode() * 31 + shapes.hashCode();//TODO cache
+  }
+
+  @Override
+  public String toString() {
+    return "GeoCompositeMembershipShape: {" + shapes + '}';
+  }
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCompositePolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCompositePolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCompositePolygon.java
new file mode 100644
index 0000000..920d3fb
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCompositePolygon.java
@@ -0,0 +1,31 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * GeoCompositePolygon is a specific implementation of GeoMembershipShape, which implements GeoPolygon explicitly.
+ *
+ * @lucene.experimental
+ */
+public class GeoCompositePolygon extends GeoCompositeMembershipShape implements GeoPolygon {
+  /** Constructor.
+   */
+  public GeoCompositePolygon() {
+  }
+
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoConvexPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoConvexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoConvexPolygon.java
new file mode 100755
index 0000000..fb024b6
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoConvexPolygon.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.spatial3d.geom;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.List;
+
+/**
+ * GeoConvexPolygon objects are generic building blocks of more complex structures.
+ * The only restrictions on these objects are: (1) they must be convex; (2) they must have
+ * a maximum extent no larger than PI.  Violating either one of these limits will
+ * cause the logic to fail.
+ *
+ * @lucene.experimental
+ */
+public class GeoConvexPolygon extends GeoBasePolygon {
+  /** The list of polygon points */
+  protected final List<GeoPoint> points;
+  /** A bitset describing, for each edge, whether it is internal or not */
+  protected final BitSet isInternalEdges;
+
+  /** A list of edges */
+  protected SidedPlane[] edges = null;
+  /** The set of notable points for each edge */
+  protected GeoPoint[][] notableEdgePoints = null;
+  /** A point which is on the boundary of the polygon */
+  protected GeoPoint[] edgePoints = null;
+  /** Tracking the maximum distance we go at any one time, so to be sure it's legal */
+  protected double fullDistance = 0.0;
+  /** Set to true when the polygon is complete */
+  protected boolean isDone = false;
+  
+  /**
+   * Create a convex polygon from a list of points.  The first point must be on the
+   * external edge.
+   *@param planetModel is the planet model.
+   *@param pointList is the list of points to create the polygon from.
+   */
+  public GeoConvexPolygon(final PlanetModel planetModel, final List<GeoPoint> pointList) {
+    super(planetModel);
+    this.points = pointList;
+    this.isInternalEdges = new BitSet();
+    done(false);
+  }
+
+  /**
+   * Create a convex polygon from a list of points, keeping track of which boundaries
+   * are internal.  This is used when creating a polygon as a building block for another shape.
+   *@param planetModel is the planet model.
+   *@param pointList is the set of points to create the polygon from.
+   *@param internalEdgeFlags is a bitset describing whether each edge is internal or not.
+   *@param returnEdgeInternal is true when the final return edge is an internal one.
+   */
+  public GeoConvexPolygon(final PlanetModel planetModel, final List<GeoPoint> pointList, final BitSet internalEdgeFlags,
+                          final boolean returnEdgeInternal) {
+    super(planetModel);
+    this.points = pointList;
+    this.isInternalEdges = internalEdgeFlags;
+    done(returnEdgeInternal);
+  }
+
+  /**
+   * Create a convex polygon, with a starting latitude and longitude.
+   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
+   *@param planetModel is the planet model.
+   *@param startLatitude is the latitude of the first point.
+   *@param startLongitude is the longitude of the first point.
+   */
+  public GeoConvexPolygon(final PlanetModel planetModel, final double startLatitude, final double startLongitude) {
+    super(planetModel);
+    points = new ArrayList<>();
+    isInternalEdges = new BitSet();
+    points.add(new GeoPoint(planetModel, startLatitude, startLongitude));
+  }
+
+  /**
+   * Add a point to the polygon.
+   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
+   *
+   * @param latitude       is the latitude of the next point.
+   * @param longitude      is the longitude of the next point.
+   * @param isInternalEdge is true if the edge just added with this point should be considered "internal", and not
+   *                       intersected as part of the intersects() operation.
+   */
+  public void addPoint(final double latitude, final double longitude, final boolean isInternalEdge) {
+    if (isDone)
+      throw new IllegalStateException("Can't call addPoint() if done() already called");
+    if (isInternalEdge)
+      isInternalEdges.set(points.size() - 1);
+    points.add(new GeoPoint(planetModel, latitude, longitude));
+  }
+
+  /**
+   * Finish the polygon, by connecting the last added point with the starting point.
+   *@param isInternalReturnEdge is true if the return edge (back to start) is an internal one.
+   */
+  public void done(final boolean isInternalReturnEdge) {
+    if (isDone)
+      throw new IllegalStateException("Can't call done() more than once");
+    // If fewer than 3 points, can't do it.
+    if (points.size() < 3)
+      throw new IllegalArgumentException("Polygon needs at least three points.");
+
+    if (isInternalReturnEdge)
+      isInternalEdges.set(points.size() - 1);
+
+    isDone = true;
+    
+    // Time to construct the planes.  If the polygon is truly convex, then any adjacent point
+    // to a segment can provide an interior measurement.
+    edges = new SidedPlane[points.size()];
+    notableEdgePoints = new GeoPoint[points.size()][];
+
+    for (int i = 0; i < points.size(); i++) {
+      final GeoPoint start = points.get(i);
+      final GeoPoint end = points.get(legalIndex(i + 1));
+      final double distance = start.arcDistance(end);
+      if (distance > fullDistance)
+        fullDistance = distance;
+      final GeoPoint check = points.get(legalIndex(i + 2));
+      final SidedPlane sp = new SidedPlane(check, start, end);
+      //System.out.println("Created edge "+sp+" using start="+start+" end="+end+" check="+check);
+      edges[i] = sp;
+      notableEdgePoints[i] = new GeoPoint[]{start, end};
+    }
+    createCenterPoint();
+  }
+
+  /** Compute a reasonable center point.
+   */
+  protected void createCenterPoint() {
+    // In order to naively confirm that the polygon is convex, I would need to
+    // check every edge, and verify that every point (other than the edge endpoints)
+    // is within the edge's sided plane.  This is an order n^2 operation.  That's still
+    // not wrong, though, because everything else about polygons has a similar cost.
+    for (int edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
+      final SidedPlane edge = edges[edgeIndex];
+      for (int pointIndex = 0; pointIndex < points.size(); pointIndex++) {
+        if (pointIndex != edgeIndex && pointIndex != legalIndex(edgeIndex + 1)) {
+          if (!edge.isWithin(points.get(pointIndex)))
+            throw new IllegalArgumentException("Polygon is not convex: Point " + points.get(pointIndex) + " Edge " + edge);
+        }
+      }
+    }
+    edgePoints = new GeoPoint[]{points.get(0)};
+  }
+
+  /** Compute a legal point index from a possibly illegal one, that may have wrapped.
+   *@param index is the index.
+   *@return the normalized index.
+   */
+  protected int legalIndex(int index) {
+    while (index >= points.size())
+      index -= points.size();
+    return index;
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    for (final SidedPlane edge : edges) {
+      if (!edge.isWithin(x, y, z))
+        return false;
+    }
+    return true;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    //System.err.println("Checking for polygon intersection with plane "+p+"...");
+    for (int edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
+      final SidedPlane edge = edges[edgeIndex];
+      final GeoPoint[] points = this.notableEdgePoints[edgeIndex];
+      if (!isInternalEdges.get(edgeIndex)) {
+        //System.err.println(" non-internal edge "+edge);
+        // Edges flagged as 'internal only' are excluded from the matching
+        // Construct boundaries
+        final Membership[] membershipBounds = new Membership[edges.length - 1];
+        int count = 0;
+        for (int otherIndex = 0; otherIndex < edges.length; otherIndex++) {
+          if (otherIndex != edgeIndex) {
+            membershipBounds[count++] = edges[otherIndex];
+          }
+        }
+        if (edge.intersects(planetModel, p, notablePoints, points, bounds, membershipBounds)) {
+          //System.err.println(" intersects!");
+          return true;
+        }
+      }
+    }
+    //System.err.println(" no intersection");
+    return false;
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+
+    // Add all the points
+    for (final GeoPoint point : points) {
+      bounds.addPoint(point);
+    }
+
+    // Add planes with membership.
+    for (int edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
+      final SidedPlane edge = edges[edgeIndex];
+      // Construct boundaries
+      final Membership[] membershipBounds = new Membership[edges.length - 1];
+      int count = 0;
+      for (int otherIndex = 0; otherIndex < edges.length; otherIndex++) {
+        if (otherIndex != edgeIndex) {
+          membershipBounds[count++] = edges[otherIndex];
+        }
+      }
+      bounds.addPlane(planetModel, edge, membershipBounds);
+    }
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    double minimumDistance = Double.MAX_VALUE;
+    for (final GeoPoint edgePoint : points) {
+      final double newDist = distanceStyle.computeDistance(edgePoint, x,y,z);
+      if (newDist < minimumDistance) {
+        minimumDistance = newDist;
+      }
+    }
+    for (int edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
+      final Plane edgePlane = edges[edgeIndex];
+      final Membership[] membershipBounds = new Membership[edges.length - 1];
+      int count = 0;
+      for (int otherIndex = 0; otherIndex < edges.length; otherIndex++) {
+        if (otherIndex != edgeIndex) {
+          membershipBounds[count++] = edges[otherIndex];
+        }
+      }
+      final double newDist = distanceStyle.computeDistance(planetModel, edgePlane, x, y, z, membershipBounds);
+      if (newDist < minimumDistance) {
+        minimumDistance = newDist;
+      }
+    }
+    return minimumDistance;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoConvexPolygon))
+      return false;
+    GeoConvexPolygon other = (GeoConvexPolygon) o;
+    if (!super.equals(other))
+      return false;
+    if (!other.isInternalEdges.equals(isInternalEdges))
+      return false;
+    return (other.points.equals(points));
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + points.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoConvexPolygon: {planetmodel=" + planetModel + ", points=" + points + "}";
+  }
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateHorizontalLine.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateHorizontalLine.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateHorizontalLine.java
new file mode 100644
index 0000000..b7de0c2
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateHorizontalLine.java
@@ -0,0 +1,215 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Degenerate bounding box limited on two sides (left lon, right lon).
+ * The left-right maximum extent for this shape is PI; for anything larger, use
+ * GeoWideDegenerateHorizontalLine.
+ *
+ * @lucene.internal
+ */
+public class GeoDegenerateHorizontalLine extends GeoBaseBBox {
+  /** Latitude of horizontal line */
+  protected final double latitude;
+  /** Left bounding longitude of line */
+  protected final double leftLon;
+  /** Right bounding longitude of line */
+  protected final double rightLon;
+
+  /** Left hand endpoint of line */
+  protected final GeoPoint LHC;
+  /** Right hand endpoint of line */
+  protected final GeoPoint RHC;
+
+  /** The plane describing the line */
+  protected final Plane plane;
+  /** The left side end plane */
+  protected final SidedPlane leftPlane;
+  /** The right side end plane */
+  protected final SidedPlane rightPlane;
+
+  /** Notable points for the line */
+  protected final GeoPoint[] planePoints;
+
+  /** Center of line */
+  protected final GeoPoint centerPoint;
+  /** A point that's on the line */
+  protected final GeoPoint[] edgePoints;
+
+  /**
+   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
+   *@param planetModel is the planet model.
+   *@param latitude is the latitude of the line.
+   *@param leftLon is the left end longitude.
+   *@param rightLon is the right end longitude.
+   */
+  public GeoDegenerateHorizontalLine(final PlanetModel planetModel, final double latitude, final double leftLon, double rightLon) {
+    super(planetModel);
+    // Argument checking
+    if (latitude > Math.PI * 0.5 || latitude < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Latitude out of range");
+    if (leftLon < -Math.PI || leftLon > Math.PI)
+      throw new IllegalArgumentException("Left longitude out of range");
+    if (rightLon < -Math.PI || rightLon > Math.PI)
+      throw new IllegalArgumentException("Right longitude out of range");
+    double extent = rightLon - leftLon;
+    if (extent < 0.0) {
+      extent += 2.0 * Math.PI;
+    }
+    if (extent > Math.PI)
+      throw new IllegalArgumentException("Width of rectangle too great");
+
+    this.latitude = latitude;
+    this.leftLon = leftLon;
+    this.rightLon = rightLon;
+
+    final double sinLatitude = Math.sin(latitude);
+    final double cosLatitude = Math.cos(latitude);
+    final double sinLeftLon = Math.sin(leftLon);
+    final double cosLeftLon = Math.cos(leftLon);
+    final double sinRightLon = Math.sin(rightLon);
+    final double cosRightLon = Math.cos(rightLon);
+
+    // Now build the two points
+    this.LHC = new GeoPoint(planetModel, sinLatitude, sinLeftLon, cosLatitude, cosLeftLon, latitude, leftLon);
+    this.RHC = new GeoPoint(planetModel, sinLatitude, sinRightLon, cosLatitude, cosRightLon, latitude, rightLon);
+
+    this.plane = new Plane(planetModel, sinLatitude);
+
+    // Normalize
+    while (leftLon > rightLon) {
+      rightLon += Math.PI * 2.0;
+    }
+    final double middleLon = (leftLon + rightLon) * 0.5;
+    final double sinMiddleLon = Math.sin(middleLon);
+    final double cosMiddleLon = Math.cos(middleLon);
+
+    this.centerPoint = new GeoPoint(planetModel, sinLatitude, sinMiddleLon, cosLatitude, cosMiddleLon);
+    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
+    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
+
+    this.planePoints = new GeoPoint[]{LHC, RHC};
+
+    this.edgePoints = new GeoPoint[]{centerPoint};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    double newTopLat = latitude + angle;
+    double newBottomLat = latitude - angle;
+    // Figuring out when we escalate to a special case requires some prefiguring
+    double currentLonSpan = rightLon - leftLon;
+    if (currentLonSpan < 0.0)
+      currentLonSpan += Math.PI * 2.0;
+    double newLeftLon = leftLon - angle;
+    double newRightLon = rightLon + angle;
+    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
+      newLeftLon = -Math.PI;
+      newRightLon = Math.PI;
+    }
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return plane.evaluateIsZero(x, y, z) &&
+        leftPlane.isWithin(x, y, z) &&
+        rightPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public double getRadius() {
+    double topAngle = centerPoint.arcDistance(RHC);
+    double bottomAngle = centerPoint.arcDistance(LHC);
+    return Math.max(topAngle, bottomAngle);
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    return centerPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return p.intersects(planetModel, plane, notablePoints, planePoints, bounds, leftPlane, rightPlane);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds.addHorizontalPlane(planetModel, latitude, plane, leftPlane, rightPlane)
+      .addPoint(LHC).addPoint(RHC);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    //System.err.println("getting relationship between "+this+" and "+path);
+    if (path.intersects(plane, planePoints, leftPlane, rightPlane)) {
+      //System.err.println(" overlaps");
+      return OVERLAPS;
+    }
+
+    if (path.isWithin(centerPoint)) {
+      //System.err.println(" contains");
+      return CONTAINS;
+    }
+
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    final double distance = distanceStyle.computeDistance(planetModel, plane, x,y,z, leftPlane, rightPlane);
+    
+    final double LHCDistance = distanceStyle.computeDistance(LHC, x,y,z);
+    final double RHCDistance = distanceStyle.computeDistance(RHC, x,y,z);
+    
+    return Math.min(
+      distance,
+      Math.min(LHCDistance, RHCDistance));
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoDegenerateHorizontalLine))
+      return false;
+    GeoDegenerateHorizontalLine other = (GeoDegenerateHorizontalLine) o;
+    return super.equals(other) && other.LHC.equals(LHC) && other.RHC.equals(RHC);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + LHC.hashCode();
+    result = 31 * result + RHC.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoDegenerateHorizontalLine: {planetmodel="+planetModel+", latitude=" + latitude + "(" + latitude * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightLon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
+  }
+}
+  
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateLatitudeZone.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateLatitudeZone.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateLatitudeZone.java
new file mode 100644
index 0000000..e794123
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateLatitudeZone.java
@@ -0,0 +1,138 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * This GeoBBox represents an area rectangle of one specific latitude with
+ * no longitude bounds.
+ *
+ * @lucene.internal
+ */
+public class GeoDegenerateLatitudeZone extends GeoBaseBBox {
+  /** The latitude */
+  protected final double latitude;
+  /** Sine of the latitude */
+  protected final double sinLatitude;
+  /** Plane describing the latitude zone */
+  protected final Plane plane;
+  /** A point on the world that's also on the zone */
+  protected final GeoPoint interiorPoint;
+  /** An array consisting of the interiorPoint */
+  protected final GeoPoint[] edgePoints;
+  /** No notable points */
+  protected final static GeoPoint[] planePoints = new GeoPoint[0];
+
+  /** Constructor.
+   *@param planetModel is the planet model to use.
+   *@param latitude is the latitude of the latitude zone.
+   */
+  public GeoDegenerateLatitudeZone(final PlanetModel planetModel, final double latitude) {
+    super(planetModel);
+    this.latitude = latitude;
+
+    this.sinLatitude = Math.sin(latitude);
+    double cosLatitude = Math.cos(latitude);
+    this.plane = new Plane(planetModel, sinLatitude);
+    // Compute an interior point.
+    interiorPoint = new GeoPoint(planetModel, sinLatitude, 0.0, cosLatitude, 1.0);
+    edgePoints = new GeoPoint[]{interiorPoint};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    double newTopLat = latitude + angle;
+    double newBottomLat = latitude - angle;
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, -Math.PI, Math.PI);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return Math.abs(z - this.sinLatitude) < 1e-10;
+  }
+
+  @Override
+  public double getRadius() {
+    return Math.PI;
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    // Totally arbitrary
+    return interiorPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return p.intersects(planetModel, plane, notablePoints, planePoints, bounds);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds.noLongitudeBound()
+      .addHorizontalPlane(planetModel, latitude, plane);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    // Second, the shortcut of seeing whether endpoints are in/out is not going to
+    // work with no area endpoints.  So we rely entirely on intersections.
+    //System.out.println("Got here! latitude="+latitude+" path="+path);
+
+    if (path.intersects(plane, planePoints)) {
+      return OVERLAPS;
+    }
+
+    if (path.isWithin(interiorPoint)) {
+      return CONTAINS;
+    }
+
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    return distanceStyle.computeDistance(planetModel, plane, x,y,z);
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoDegenerateLatitudeZone))
+      return false;
+    GeoDegenerateLatitudeZone other = (GeoDegenerateLatitudeZone) o;
+    return super.equals(other) && other.latitude == latitude;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    long temp = Double.doubleToLongBits(latitude);
+    result = 31 * result + (int) (temp ^ (temp >>> 32));
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoDegenerateLatitudeZone: {planetmodel="+planetModel+", lat=" + latitude + "(" + latitude * 180.0 / Math.PI + ")}";
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateLongitudeSlice.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateLongitudeSlice.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateLongitudeSlice.java
new file mode 100644
index 0000000..0bb7b90
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateLongitudeSlice.java
@@ -0,0 +1,153 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Degenerate longitude slice.
+ *
+ * @lucene.internal
+ */
+public class GeoDegenerateLongitudeSlice extends GeoBaseBBox {
+  /** The longitude of the slice */
+  protected final double longitude;
+
+  /** The bounding plane for the slice (through both poles, perpendicular to the slice) */
+  protected final SidedPlane boundingPlane;
+  /** The plane of the slice */
+  protected final Plane plane;
+  /** A point on the slice */
+  protected final GeoPoint interiorPoint;
+  /** An array consisting of the one point chosen on the slice */
+  protected final GeoPoint[] edgePoints;
+  /** Notable points for the slice (north and south poles) */
+  protected final GeoPoint[] planePoints;
+
+  /**
+   * Accepts only values in the following ranges: lon: {@code -PI -> PI}
+   */
+  public GeoDegenerateLongitudeSlice(final PlanetModel planetModel, final double longitude) {
+    super(planetModel);
+    // Argument checking
+    if (longitude < -Math.PI || longitude > Math.PI)
+      throw new IllegalArgumentException("Longitude out of range");
+    this.longitude = longitude;
+
+    final double sinLongitude = Math.sin(longitude);
+    final double cosLongitude = Math.cos(longitude);
+
+    this.plane = new Plane(cosLongitude, sinLongitude);
+    // We need a bounding plane too, which is perpendicular to the longitude plane and sided so that the point (0.0, longitude) is inside.
+    this.interiorPoint = new GeoPoint(planetModel, 0.0, sinLongitude, 1.0, cosLongitude);
+    this.boundingPlane = new SidedPlane(interiorPoint, -sinLongitude, cosLongitude);
+    this.edgePoints = new GeoPoint[]{interiorPoint};
+    this.planePoints = new GeoPoint[]{planetModel.NORTH_POLE, planetModel.SOUTH_POLE};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    // Figuring out when we escalate to a special case requires some prefiguring
+    double newLeftLon = longitude - angle;
+    double newRightLon = longitude + angle;
+    double currentLonSpan = 2.0 * angle;
+    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
+      newLeftLon = -Math.PI;
+      newRightLon = Math.PI;
+    }
+    return GeoBBoxFactory.makeGeoBBox(planetModel, Math.PI * 0.5, -Math.PI * 0.5, newLeftLon, newRightLon);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return plane.evaluateIsZero(x, y, z) &&
+        boundingPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public double getRadius() {
+    return Math.PI * 0.5;
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    return interiorPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return p.intersects(planetModel, plane, notablePoints, planePoints, bounds, boundingPlane);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds
+      .addVerticalPlane(planetModel, longitude, plane, boundingPlane)
+      .addPoint(planetModel.NORTH_POLE).addPoint(planetModel.SOUTH_POLE);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    // Look for intersections.
+    if (path.intersects(plane, planePoints, boundingPlane))
+      return OVERLAPS;
+
+    if (path.isWithin(interiorPoint))
+      return CONTAINS;
+
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    final double distance = distanceStyle.computeDistance(planetModel, plane, x,y,z, boundingPlane);
+    
+    final double northDistance = distanceStyle.computeDistance(planetModel.NORTH_POLE, x,y,z);
+    final double southDistance = distanceStyle.computeDistance(planetModel.SOUTH_POLE, x,y,z);
+    
+    return Math.min(
+      distance,
+      Math.min(northDistance, southDistance));
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoDegenerateLongitudeSlice))
+      return false;
+    GeoDegenerateLongitudeSlice other = (GeoDegenerateLongitudeSlice) o;
+    return super.equals(other) && other.longitude == longitude;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    long temp = Double.doubleToLongBits(longitude);
+    result = result * 31 + (int) (temp ^ (temp >>> 32));
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoDegenerateLongitudeSlice: {planetmodel="+planetModel+", longitude=" + longitude + "(" + longitude * 180.0 / Math.PI + ")}";
+  }
+}
+  
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegeneratePoint.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegeneratePoint.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegeneratePoint.java
new file mode 100644
index 0000000..fcd2037
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegeneratePoint.java
@@ -0,0 +1,135 @@
+/*
+ * 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.spatial3d.geom;
+    
+/**
+ * This class represents a degenerate point bounding box.
+ * It is not a simple GeoPoint because we must have the latitude and longitude.
+ *
+ * @lucene.internal
+ */
+public class GeoDegeneratePoint extends GeoPoint implements GeoBBox, GeoCircle {
+  /** Current planet model, since we don't extend BasePlanetObject */
+  protected final PlanetModel planetModel;
+  /** Edge point is an area containing just this */
+  protected final GeoPoint[] edgePoints;
+
+  /** Constructor.
+   *@param planetModel is the planet model to use.
+   *@param lat is the latitude.
+   *@param lon is the longitude.
+   */
+  public GeoDegeneratePoint(final PlanetModel planetModel, final double lat, final double lon) {
+    super(planetModel, lat, lon);
+    this.planetModel = planetModel;
+    this.edgePoints = new GeoPoint[]{this};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    final double newTopLat = latitude + angle;
+    final double newBottomLat = latitude - angle;
+    final double newLeftLon = longitude - angle;
+    final double newRightLon = longitude + angle;
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane plane, final GeoPoint[] notablePoints, final Membership... bounds) {
+    // If not on the plane, no intersection
+    if (!plane.evaluateIsZero(this))
+      return false;
+
+    for (Membership m : bounds) {
+      if (!m.isWithin(this))
+        return false;
+    }
+    return true;
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    bounds.addPoint(this);
+  }
+
+  @Override
+  public double computeOutsideDistance(final DistanceStyle distanceStyle, final GeoPoint point) {
+    return distanceStyle.computeDistance(this, point);
+  }
+
+  @Override
+  public double computeOutsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    return distanceStyle.computeDistance(this, x,y,z);
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoDegeneratePoint))
+      return false;
+    GeoDegeneratePoint other = (GeoDegeneratePoint) o;
+    return super.equals(other) && other.latitude == latitude && other.longitude == longitude;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoDegeneratePoint: {planetmodel="+planetModel+", lat=" + latitude + "(" + latitude * 180.0 / Math.PI + "), lon=" + longitude + "(" + longitude * 180.0 / Math.PI + ")}";
+  }
+
+  @Override
+  public boolean isWithin(final Vector point) {
+    return isWithin(point.x, point.y, point.z);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return x == this.x && y == this.y && z == this.z;
+  }
+
+  @Override
+  public double getRadius() {
+    return 0.0;
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    return this;
+  }
+
+  @Override
+  public int getRelationship(final GeoShape shape) {
+    if (shape.isWithin(this)) {
+      //System.err.println("Degenerate point "+this+" is WITHIN shape "+shape);
+      return CONTAINS;
+    }
+
+    //System.err.println("Degenerate point "+this+" is NOT within shape "+shape);
+    return DISJOINT;
+  }
+
+  @Override
+  public double computeDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    if (isWithin(x,y,z))
+      return 0.0;
+    return Double.MAX_VALUE;
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateVerticalLine.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateVerticalLine.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateVerticalLine.java
new file mode 100644
index 0000000..dff53b4
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateVerticalLine.java
@@ -0,0 +1,205 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Degenerate bounding box limited on two sides (top lat, bottom lat).
+ *
+ * @lucene.internal
+ */
+public class GeoDegenerateVerticalLine extends GeoBaseBBox {
+  /** Top latitude of the vertical line */
+  protected final double topLat;
+  /** Bottom latitude of the vertical line */
+  protected final double bottomLat;
+  /** Longitude of the vertical line */
+  protected final double longitude;
+
+  /** Point at the upper end of the vertical line */
+  protected final GeoPoint UHC;
+  /** Point at the lower end of the vertical line */
+  protected final GeoPoint LHC;
+
+  /** Top end cutoff plane */
+  protected final SidedPlane topPlane;
+  /** Bottom end cutoff plane */
+  protected final SidedPlane bottomPlane;
+  /** Back-side cutoff plane */
+  protected final SidedPlane boundingPlane;
+  /** The vertical line plane */
+  protected final Plane plane;
+  /** Notable points for the line (end points) */
+  protected final GeoPoint[] planePoints;
+  /** A computed center point for the line */
+  protected final GeoPoint centerPoint;
+  /** A point that's on the line */
+  protected final GeoPoint[] edgePoints;
+
+  /**
+   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, longitude: {@code -PI -> PI}
+   */
+  public GeoDegenerateVerticalLine(final PlanetModel planetModel, final double topLat, final double bottomLat, final double longitude) {
+    super(planetModel);
+    // Argument checking
+    if (topLat > Math.PI * 0.5 || topLat < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Top latitude out of range");
+    if (bottomLat > Math.PI * 0.5 || bottomLat < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Bottom latitude out of range");
+    if (topLat < bottomLat)
+      throw new IllegalArgumentException("Top latitude less than bottom latitude");
+    if (longitude < -Math.PI || longitude > Math.PI)
+      throw new IllegalArgumentException("Longitude out of range");
+
+    this.topLat = topLat;
+    this.bottomLat = bottomLat;
+    this.longitude = longitude;
+
+    final double sinTopLat = Math.sin(topLat);
+    final double cosTopLat = Math.cos(topLat);
+    final double sinBottomLat = Math.sin(bottomLat);
+    final double cosBottomLat = Math.cos(bottomLat);
+    final double sinLongitude = Math.sin(longitude);
+    final double cosLongitude = Math.cos(longitude);
+
+    // Now build the two points
+    this.UHC = new GeoPoint(planetModel, sinTopLat, sinLongitude, cosTopLat, cosLongitude, topLat, longitude);
+    this.LHC = new GeoPoint(planetModel, sinBottomLat, sinLongitude, cosBottomLat, cosLongitude, bottomLat, longitude);
+
+    this.plane = new Plane(cosLongitude, sinLongitude);
+
+    final double middleLat = (topLat + bottomLat) * 0.5;
+    final double sinMiddleLat = Math.sin(middleLat);
+    final double cosMiddleLat = Math.cos(middleLat);
+
+    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinLongitude, cosMiddleLat, cosLongitude);
+
+    this.topPlane = new SidedPlane(centerPoint, planetModel, sinTopLat);
+    this.bottomPlane = new SidedPlane(centerPoint, planetModel, sinBottomLat);
+
+    this.boundingPlane = new SidedPlane(centerPoint, -sinLongitude, cosLongitude);
+
+    this.planePoints = new GeoPoint[]{UHC, LHC};
+
+    this.edgePoints = new GeoPoint[]{centerPoint};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    final double newTopLat = topLat + angle;
+    final double newBottomLat = bottomLat - angle;
+    double newLeftLon = longitude - angle;
+    double newRightLon = longitude + angle;
+    double currentLonSpan = 2.0 * angle;
+    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
+      newLeftLon = -Math.PI;
+      newRightLon = Math.PI;
+    }
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return plane.evaluateIsZero(x, y, z) &&
+        boundingPlane.isWithin(x, y, z) &&
+        topPlane.isWithin(x, y, z) &&
+        bottomPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public double getRadius() {
+    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
+    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
+    // the distance to the right or left edge from the center.
+    final double topAngle = centerPoint.arcDistance(UHC);
+    final double bottomAngle = centerPoint.arcDistance(LHC);
+    return Math.max(topAngle, bottomAngle);
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    return centerPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return p.intersects(planetModel, plane, notablePoints, planePoints, bounds, boundingPlane, topPlane, bottomPlane);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds.addVerticalPlane(planetModel, longitude, plane, boundingPlane, topPlane, bottomPlane)
+      .addPoint(UHC).addPoint(LHC);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    //System.err.println(this+" relationship to "+path);
+    if (path.intersects(plane, planePoints, boundingPlane, topPlane, bottomPlane)) {
+      //System.err.println(" overlaps");
+      return OVERLAPS;
+    }
+
+    if (path.isWithin(centerPoint)) {
+      //System.err.println(" contains");
+      return CONTAINS;
+    }
+
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    final double distance = distanceStyle.computeDistance(planetModel, plane, x,y,z, topPlane, bottomPlane, boundingPlane);
+    
+    final double UHCDistance = distanceStyle.computeDistance(UHC, x,y,z);
+    final double LHCDistance = distanceStyle.computeDistance(LHC, x,y,z);
+    
+    return Math.min(
+      distance,
+      Math.min(UHCDistance, LHCDistance));
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoDegenerateVerticalLine))
+      return false;
+    GeoDegenerateVerticalLine other = (GeoDegenerateVerticalLine) o;
+    return super.equals(other) && other.UHC.equals(UHC) && other.LHC.equals(LHC);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + UHC.hashCode();
+    result = 31 * result + LHC.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoDegenerateVerticalLine: {longitude=" + longitude + "(" + longitude * 180.0 / Math.PI + "), toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + "), bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + ")}";
+  }
+}
+  
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDistance.java
new file mode 100755
index 0000000..d41dd51
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDistance.java
@@ -0,0 +1,59 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * An implementer of this interface is capable of computing the described "distance" values,
+ * which are meant to provide both actual distance values, as well as
+ * distance estimates that can be computed more cheaply.
+ *
+ * @lucene.experimental
+ */
+public interface GeoDistance extends Membership {
+  
+  // The following methods compute distances from the shape to a point
+  // expected to be INSIDE the shape.  Typically a value of Double.MAX_VALUE
+  // is returned for points that happen to be outside the shape.
+
+  /**
+   * Compute this shape's <em>internal</em> "distance" to the GeoPoint.
+   * Implementations should clarify how this is computed when it's non-obvious.
+   * A return value of Double.MAX_VALUE should be returned for
+   * points outside of the shape.
+   *
+   * @param distanceStyle is the distance style.
+   * @param point is the point to compute the distance to.
+   * @return the distance.
+   */
+  public default double computeDistance(final DistanceStyle distanceStyle, final GeoPoint point) {
+    return computeDistance(distanceStyle, point.x, point.y, point.z);
+  }
+
+  /**
+   * Compute this shape's <em>internal</em> "distance" to the GeoPoint.
+   * Implementations should clarify how this is computed when it's non-obvious.
+   * A return value of Double.MAX_VALUE should be returned for
+   * points outside of the shape.
+   *
+   * @param x is the point's unit x coordinate (using U.S. convention).
+   * @param y is the point's unit y coordinate (using U.S. convention).
+   * @param z is the point's unit z coordinate (using U.S. convention).
+   * @return the distance.
+   */
+  public double computeDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z);
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDistanceShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDistanceShape.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDistanceShape.java
new file mode 100755
index 0000000..e7b0348
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDistanceShape.java
@@ -0,0 +1,27 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Distance shapes have capabilities of both geohashing and distance
+ * computation (which also includes point membership determination).
+ *
+ * @lucene.experimental
+ */
+public interface GeoDistanceShape extends GeoMembershipShape, GeoDistance {
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoLatitudeZone.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoLatitudeZone.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoLatitudeZone.java
new file mode 100755
index 0000000..912ca32
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoLatitudeZone.java
@@ -0,0 +1,198 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * This GeoBBox represents an area rectangle limited only in latitude.
+ *
+ * @lucene.internal
+ */
+public class GeoLatitudeZone extends GeoBaseBBox {
+  /** The top latitude of the zone */
+  protected final double topLat;
+  /** The bottom latitude of the zone */
+  protected final double bottomLat;
+  /** Cosine of the top lat */
+  protected final double cosTopLat;
+  /** Cosine of the bottom lat */
+  protected final double cosBottomLat;
+  /** The top plane */
+  protected final SidedPlane topPlane;
+  /** The bottom plane */
+  protected final SidedPlane bottomPlane;
+  /** An interior point */
+  protected final GeoPoint interiorPoint;
+  /** Notable points (none) */
+  protected final static GeoPoint[] planePoints = new GeoPoint[0];
+
+  // We need two additional points because a latitude zone's boundaries don't intersect.  This is a very
+  // special case that most GeoBBox's do not have.
+  
+  /** Top boundary point */
+  protected final GeoPoint topBoundaryPoint;
+  /** Bottom boundary point */
+  protected final GeoPoint bottomBoundaryPoint;
+  /** A point on each distinct edge */
+  protected final GeoPoint[] edgePoints;
+
+  /** Constructor.
+   *@param planetModel is the planet model to use.
+   *@param topLat is the top latitude.
+   *@param bottomLat is the bottom latitude.
+   */
+  public GeoLatitudeZone(final PlanetModel planetModel, final double topLat, final double bottomLat) {
+    super(planetModel);
+    this.topLat = topLat;
+    this.bottomLat = bottomLat;
+
+    final double sinTopLat = Math.sin(topLat);
+    final double sinBottomLat = Math.sin(bottomLat);
+    this.cosTopLat = Math.cos(topLat);
+    this.cosBottomLat = Math.cos(bottomLat);
+
+    // Compute an interior point.  Pick one whose lat is between top and bottom.
+    final double middleLat = (topLat + bottomLat) * 0.5;
+    final double sinMiddleLat = Math.sin(middleLat);
+    this.interiorPoint = new GeoPoint(planetModel, sinMiddleLat, 0.0, Math.sqrt(1.0 - sinMiddleLat * sinMiddleLat), 1.0);
+    this.topBoundaryPoint = new GeoPoint(planetModel, sinTopLat, 0.0, Math.sqrt(1.0 - sinTopLat * sinTopLat), 1.0);
+    this.bottomBoundaryPoint = new GeoPoint(planetModel, sinBottomLat, 0.0, Math.sqrt(1.0 - sinBottomLat * sinBottomLat), 1.0);
+
+    this.topPlane = new SidedPlane(interiorPoint, planetModel, sinTopLat);
+    this.bottomPlane = new SidedPlane(interiorPoint, planetModel, sinBottomLat);
+
+    this.edgePoints = new GeoPoint[]{topBoundaryPoint, bottomBoundaryPoint};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    final double newTopLat = topLat + angle;
+    final double newBottomLat = bottomLat - angle;
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, -Math.PI, Math.PI);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return topPlane.isWithin(x, y, z) &&
+        bottomPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public double getRadius() {
+    // This is a bit tricky.  I guess we should interpret this as meaning the angle of a circle that
+    // would contain all the bounding box points, when starting in the "center".
+    if (topLat > 0.0 && bottomLat < 0.0)
+      return Math.PI;
+    double maxCosLat = cosTopLat;
+    if (maxCosLat < cosBottomLat)
+      maxCosLat = cosBottomLat;
+    return maxCosLat * Math.PI;
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    // This is totally arbitrary and only a cartesian could agree with it.
+    return interiorPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return p.intersects(planetModel, topPlane, notablePoints, planePoints, bounds, bottomPlane) ||
+        p.intersects(planetModel, bottomPlane, notablePoints, planePoints, bounds, topPlane);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds.noLongitudeBound()
+      .addHorizontalPlane(planetModel, topLat, topPlane)
+      .addHorizontalPlane(planetModel, bottomLat, bottomPlane);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    final int insideRectangle = isShapeInsideBBox(path);
+    if (insideRectangle == SOME_INSIDE)
+      return OVERLAPS;
+
+    final boolean topBoundaryInsideShape = path.isWithin(topBoundaryPoint);
+    final boolean bottomBoundaryInsideShape = path.isWithin(bottomBoundaryPoint);
+
+    if (topBoundaryInsideShape && !bottomBoundaryInsideShape ||
+        !topBoundaryInsideShape && bottomBoundaryInsideShape)
+      return OVERLAPS;
+
+    final boolean insideShape = topBoundaryInsideShape && bottomBoundaryInsideShape;
+
+    if (insideRectangle == ALL_INSIDE && insideShape)
+      return OVERLAPS;
+
+    // Second, the shortcut of seeing whether endpoints are in/out is not going to
+    // work with no area endpoints.  So we rely entirely on intersections.
+
+    if (path.intersects(topPlane, planePoints, bottomPlane) ||
+        path.intersects(bottomPlane, planePoints, topPlane))
+      return OVERLAPS;
+
+    // There is another case for latitude zones only.  This is when the boundaries of the shape all fit
+    // within the zone, but the shape includes areas outside the zone crossing a pole.
+    // In this case, the above "overlaps" check is insufficient.  We also need to check a point on either boundary
+    // whether it is within the shape.  If both such points are within, then CONTAINS is the right answer.  If
+    // one such point is within, then OVERLAPS is the right answer.
+
+    if (insideShape)
+      return CONTAINS;
+
+    if (insideRectangle == ALL_INSIDE)
+      return WITHIN;
+
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    final double topDistance = distanceStyle.computeDistance(planetModel, topPlane, x,y,z, bottomPlane);
+    final double bottomDistance = distanceStyle.computeDistance(planetModel, bottomPlane, x,y,z, topPlane);
+
+    return Math.min(topDistance, bottomDistance);
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoLatitudeZone))
+      return false;
+    GeoLatitudeZone other = (GeoLatitudeZone) o;
+    return super.equals(other) && other.topBoundaryPoint.equals(topBoundaryPoint) && other.bottomBoundaryPoint.equals(bottomBoundaryPoint);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + topBoundaryPoint.hashCode();
+    result = 31 * result + bottomBoundaryPoint.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoLatitudeZone: {planetmodel="+planetModel+", toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + "), bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + ")}";
+  }
+}


[02/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 0093e26)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/test/org/apache/lucene/geo3d/PlaneTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/PlaneTest.java b/lucene/spatial3d/src/test/org/apache/lucene/geo3d/PlaneTest.java
deleted file mode 100644
index 2ac3856..0000000
--- a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/PlaneTest.java
+++ /dev/null
@@ -1,64 +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.geo3d;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-/**
- * Test basic plane functionality.
- */
-public class PlaneTest {
-
-
-  @Test
-  public void testIdenticalPlanes() {
-    final GeoPoint p = new GeoPoint(PlanetModel.SPHERE, 0.123, -0.456);
-    final Plane plane1 = new Plane(p, 0.0);
-    final Plane plane2 = new Plane(p, 0.0);
-    assertTrue(plane1.isNumericallyIdentical(plane2));
-    final Plane plane3 = new Plane(p, 0.1);
-    assertFalse(plane1.isNumericallyIdentical(plane3));
-    final Vector v1 = new Vector(0.1, -0.732, 0.9);
-    final double constant = 0.432;
-    final Vector v2 = new Vector(v1.x * constant, v1.y * constant, v1.z * constant);
-    final Plane p1 = new Plane(v1, 0.2);
-    final Plane p2 = new Plane(v2, 0.2 * constant);
-    assertTrue(p1.isNumericallyIdentical(p2));
-  }
-
-  @Test
-  public void testInterpolation() {
-    // [X=0.35168818443386646, Y=-0.19637966197066342, Z=0.9152870857244183],
-    // [X=0.5003343189532654, Y=0.522128543226148, Z=0.6906861469771293],
-
-    final GeoPoint start = new GeoPoint(0.35168818443386646, -0.19637966197066342, 0.9152870857244183);
-    final GeoPoint end = new GeoPoint(0.5003343189532654, 0.522128543226148, 0.6906861469771293);
-
-    // [A=-0.6135342247741855, B=0.21504338363863665, C=0.28188192383666794, D=0.0, side=-1.0] internal? false;
-    final Plane p = new Plane(-0.6135342247741855, 0.21504338363863665, 0.28188192383666794, 0.0);
-
-    final GeoPoint[] points = p.interpolate(start, end, new double[]{0.25, 0.50, 0.75});
-
-    for (GeoPoint point : points) {
-      assertTrue(p.evaluateIsZero(point));
-    }
-  }
-}
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/test/org/apache/lucene/geo3d/TestGeo3DPoint.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/TestGeo3DPoint.java b/lucene/spatial3d/src/test/org/apache/lucene/geo3d/TestGeo3DPoint.java
deleted file mode 100644
index 17a4075..0000000
--- a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/TestGeo3DPoint.java
+++ /dev/null
@@ -1,801 +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.geo3d;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.apache.lucene.codecs.Codec;
-import org.apache.lucene.codecs.FilterCodec;
-import org.apache.lucene.codecs.PointsFormat;
-import org.apache.lucene.codecs.PointsReader;
-import org.apache.lucene.codecs.PointsWriter;
-import org.apache.lucene.codecs.lucene60.Lucene60PointsReader;
-import org.apache.lucene.codecs.lucene60.Lucene60PointsWriter;
-import org.apache.lucene.document.Document;
-import org.apache.lucene.document.Field;
-import org.apache.lucene.document.NumericDocValuesField;
-import org.apache.lucene.index.DirectoryReader;
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.IndexWriter;
-import org.apache.lucene.index.IndexWriterConfig;
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.index.MultiDocValues;
-import org.apache.lucene.index.NumericDocValues;
-import org.apache.lucene.index.SegmentReadState;
-import org.apache.lucene.index.SegmentWriteState;
-import org.apache.lucene.index.Term;
-import org.apache.lucene.search.IndexSearcher;
-import org.apache.lucene.search.Query;
-import org.apache.lucene.search.SimpleCollector;
-import org.apache.lucene.store.Directory;
-import org.apache.lucene.store.MockDirectoryWrapper;
-import org.apache.lucene.util.FixedBitSet;
-import org.apache.lucene.util.IOUtils;
-import org.apache.lucene.util.LuceneTestCase;
-import org.apache.lucene.util.TestUtil;
-import org.junit.BeforeClass;
-
-import com.carrotsearch.randomizedtesting.generators.RandomInts;
-
-public class TestGeo3DPoint extends LuceneTestCase {
-
-  private static boolean smallBBox;
-  
-  @BeforeClass
-  public static void beforeClass() {
-    smallBBox = random().nextBoolean();
-    if (VERBOSE) {
-      System.err.println("TEST: smallBBox=" + smallBBox);
-    }
-  }
-
-  private static Codec getCodec() {
-    if (Codec.getDefault().getName().equals("Lucene60")) {
-      int maxPointsInLeafNode = TestUtil.nextInt(random(), 16, 2048);
-      double maxMBSortInHeap = 3.0 + (3*random().nextDouble());
-      if (VERBOSE) {
-        System.out.println("TEST: using Lucene60PointsFormat with maxPointsInLeafNode=" + maxPointsInLeafNode + " and maxMBSortInHeap=" + maxMBSortInHeap);
-      }
-
-      return new FilterCodec("Lucene60", Codec.getDefault()) {
-        @Override
-        public PointsFormat pointsFormat() {
-          return new PointsFormat() {
-            @Override
-            public PointsWriter fieldsWriter(SegmentWriteState writeState) throws IOException {
-              return new Lucene60PointsWriter(writeState, maxPointsInLeafNode, maxMBSortInHeap);
-            }
-
-            @Override
-            public PointsReader fieldsReader(SegmentReadState readState) throws IOException {
-              return new Lucene60PointsReader(readState);
-            }
-          };
-        }
-      };
-    } else {
-      return Codec.getDefault();
-    }
-  }
-
-  public void testBasic() throws Exception {
-    Directory dir = getDirectory();
-    IndexWriterConfig iwc = newIndexWriterConfig();
-    iwc.setCodec(getCodec());
-    IndexWriter w = new IndexWriter(dir, iwc);
-    Document doc = new Document();
-    doc.add(new Geo3DPoint("field", toRadians(50.7345267), toRadians(-97.5303555)));
-    w.addDocument(doc);
-    IndexReader r = DirectoryReader.open(w);
-    // We can't wrap with "exotic" readers because the query must see the BKD3DDVFormat:
-    IndexSearcher s = newSearcher(r, false);
-    assertEquals(1, s.search(Geo3DPoint.newShapeQuery("field",
-                                                      GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84, toRadians(50), toRadians(-97), Math.PI/180.)), 1).totalHits);
-    w.close();
-    r.close();
-    dir.close();
-  }
-
-  private static double toRadians(double degrees) {
-    return Math.PI*(degrees/360.0);
-  }
-
-  private static PlanetModel getPlanetModel() {
-    if (random().nextBoolean()) {
-      // Use one of the earth models:
-      if (random().nextBoolean()) {
-        return PlanetModel.WGS84;
-      } else {
-        return PlanetModel.SPHERE;
-      }
-    } else {
-      // Make a randomly squashed planet:
-      double oblateness = random().nextDouble() * 0.5 - 0.25;
-      return new PlanetModel(1.0 + oblateness, 1.0 - oblateness);
-    }
-  }
-
-  private static class Cell {
-    static int nextCellID;
-
-    final Cell parent;
-    final int cellID;
-    final int xMinEnc, xMaxEnc;
-    final int yMinEnc, yMaxEnc;
-    final int zMinEnc, zMaxEnc;
-    final int splitCount;
-
-    public Cell(Cell parent,
-                int xMinEnc, int xMaxEnc,
-                int yMinEnc, int yMaxEnc,
-                int zMinEnc, int zMaxEnc,
-                int splitCount) {
-      this.parent = parent;
-      this.xMinEnc = xMinEnc;
-      this.xMaxEnc = xMaxEnc;
-      this.yMinEnc = yMinEnc;
-      this.yMaxEnc = yMaxEnc;
-      this.zMinEnc = zMinEnc;
-      this.zMaxEnc = zMaxEnc;
-      this.cellID = nextCellID++;
-      this.splitCount = splitCount;
-    }
-
-    /** Returns true if the quantized point lies within this cell, inclusive on all bounds. */
-    public boolean contains(double planetMax, GeoPoint point) {
-      int docX = Geo3DUtil.encodeValue(planetMax, point.x);
-      int docY = Geo3DUtil.encodeValue(planetMax, point.y);
-      int docZ = Geo3DUtil.encodeValue(planetMax, point.z);
-
-      return docX >= xMinEnc && docX <= xMaxEnc &&
-        docY >= yMinEnc && docY <= yMaxEnc && 
-        docZ >= zMinEnc && docZ <= zMaxEnc;
-    }
-
-    @Override
-    public String toString() {
-      return "cell=" + cellID + (parent == null ? "" : " parentCellID=" + parent.cellID) + " x: " + xMinEnc + " TO " + xMaxEnc + ", y: " + yMinEnc + " TO " + yMaxEnc + ", z: " + zMinEnc + " TO " + zMaxEnc + ", splits: " + splitCount;
-    }
-  }
-
-  private static GeoPoint quantize(double planetMax, GeoPoint point) {
-    return new GeoPoint(Geo3DUtil.decodeValueCenter(planetMax, Geo3DUtil.encodeValue(planetMax, point.x)),
-                        Geo3DUtil.decodeValueCenter(planetMax, Geo3DUtil.encodeValue(planetMax, point.y)),
-                        Geo3DUtil.decodeValueCenter(planetMax, Geo3DUtil.encodeValue(planetMax, point.z)));
-  }
-
-  /** Tests consistency of GeoArea.getRelationship vs GeoShape.isWithin */
-  public void testGeo3DRelations() throws Exception {
-
-    PlanetModel planetModel = getPlanetModel();
-
-    int numDocs = atLeast(1000);
-    if (VERBOSE) {
-      System.out.println("TEST: " + numDocs + " docs");
-    }
-
-    GeoPoint[] docs = new GeoPoint[numDocs];
-    for(int docID=0;docID<numDocs;docID++) {
-      docs[docID] = new GeoPoint(planetModel, toRadians(randomLat()), toRadians(randomLon()));
-      if (VERBOSE) {
-        System.out.println("  doc=" + docID + ": " + docs[docID]);
-      }
-    }
-
-    double planetMax = planetModel.getMaximumMagnitude();
-
-    int iters = atLeast(10);
-
-    int recurseDepth = RandomInts.randomIntBetween(random(), 5, 15);
-
-    iters = atLeast(50);
-    
-    for(int iter=0;iter<iters;iter++) {
-      GeoShape shape = randomShape(planetModel);
-
-      StringWriter sw = new StringWriter();
-      PrintWriter log = new PrintWriter(sw, true);
-
-      if (VERBOSE) {
-        log.println("TEST: iter=" + iter + " shape=" + shape);
-      }
-
-      XYZBounds bounds = new XYZBounds();
-      shape.getBounds(bounds);
-
-      // Start with the root cell that fully contains the shape:
-      Cell root = new Cell(null,
-                           Geo3DUtil.encodeValueLenient(planetMax, bounds.getMinimumX()),
-                           Geo3DUtil.encodeValueLenient(planetMax, bounds.getMaximumX()),
-                           Geo3DUtil.encodeValueLenient(planetMax, bounds.getMinimumY()),
-                           Geo3DUtil.encodeValueLenient(planetMax, bounds.getMaximumY()),
-                           Geo3DUtil.encodeValueLenient(planetMax, bounds.getMinimumZ()),
-                           Geo3DUtil.encodeValueLenient(planetMax, bounds.getMaximumZ()),
-                           0);
-
-      if (VERBOSE) {
-        log.println("  root cell: " + root);
-      }
-
-      List<Cell> queue = new ArrayList<>();
-      queue.add(root);
-      Set<Integer> hits = new HashSet<>();
-
-      while (queue.size() > 0) {
-        Cell cell = queue.get(queue.size()-1);
-        queue.remove(queue.size()-1);
-        if (VERBOSE) {
-          log.println("  cycle: " + cell + " queue.size()=" + queue.size());
-        }
-
-        if (random().nextInt(10) == 7 || cell.splitCount > recurseDepth) {
-          if (VERBOSE) {
-            log.println("    leaf");
-          }
-          // Leaf cell: brute force check all docs that fall within this cell:
-          for(int docID=0;docID<numDocs;docID++) {
-            GeoPoint point = docs[docID];
-            if (cell.contains(planetMax, point)) {
-              if (shape.isWithin(quantize(planetMax, point))) {
-                if (VERBOSE) {
-                  log.println("    check doc=" + docID + ": match!");
-                }
-                hits.add(docID);
-              } else {
-                if (VERBOSE) {
-                  log.println("    check doc=" + docID + ": no match");
-                }
-              }
-            }
-          }
-        } else {
-          
-          GeoArea xyzSolid = GeoAreaFactory.makeGeoArea(planetModel,
-                                                        Geo3DUtil.decodeValueMin(planetMax, cell.xMinEnc), Geo3DUtil.decodeValueMax(planetMax, cell.xMaxEnc),
-                                                        Geo3DUtil.decodeValueMin(planetMax, cell.yMinEnc), Geo3DUtil.decodeValueMax(planetMax, cell.yMaxEnc),
-                                                        Geo3DUtil.decodeValueMin(planetMax, cell.zMinEnc), Geo3DUtil.decodeValueMax(planetMax, cell.zMaxEnc));
-
-          if (VERBOSE) {
-            log.println("    minx="+Geo3DUtil.decodeValueMin(planetMax, cell.xMinEnc)+" maxx="+Geo3DUtil.decodeValueMax(planetMax, cell.xMaxEnc)+
-              " miny="+Geo3DUtil.decodeValueMin(planetMax, cell.yMinEnc)+" maxy="+Geo3DUtil.decodeValueMax(planetMax, cell.yMaxEnc)+
-              " minz="+Geo3DUtil.decodeValueMin(planetMax, cell.zMinEnc)+" maxz="+Geo3DUtil.decodeValueMax(planetMax, cell.zMaxEnc));
-          }
-
-          switch (xyzSolid.getRelationship(shape)) {          
-          case GeoArea.CONTAINS:
-            // Shape fully contains the cell: blindly add all docs in this cell:
-            if (VERBOSE) {
-              log.println("    GeoArea.CONTAINS: now addAll");
-            }
-            for(int docID=0;docID<numDocs;docID++) {
-              if (cell.contains(planetMax, docs[docID])) {
-                if (VERBOSE) {
-                  log.println("    addAll doc=" + docID);
-                }
-                hits.add(docID);
-              }
-            }
-            continue;
-          case GeoArea.OVERLAPS:
-            if (VERBOSE) {
-              log.println("    GeoArea.OVERLAPS: keep splitting");
-            }
-            // They do overlap but neither contains the other:
-            //log.println("    crosses1");
-            break;
-          case GeoArea.WITHIN:
-            if (VERBOSE) {
-              log.println("    GeoArea.WITHIN: keep splitting");
-            }
-            // Cell fully contains the shape:
-            //log.println("    crosses2");
-            break;
-          case GeoArea.DISJOINT:
-            // They do not overlap at all: don't recurse on this cell
-            //log.println("    outside");
-            if (VERBOSE) {
-              log.println("    GeoArea.DISJOINT: drop this cell");
-              for(int docID=0;docID<numDocs;docID++) {
-                if (cell.contains(planetMax, docs[docID])) {
-                  if (VERBOSE) {
-                    log.println("    skip doc=" + docID);
-                  }
-                }
-              }
-            }
-            continue;
-          default:
-            assert false;
-          }
-
-          // Randomly split:
-          switch(random().nextInt(3)) {
-
-          case 0:
-            // Split on X:
-            {
-              int splitValue = RandomInts.randomIntBetween(random(), cell.xMinEnc, cell.xMaxEnc);
-              if (VERBOSE) {
-                log.println("    now split on x=" + splitValue);
-              }
-              Cell cell1 = new Cell(cell,
-                                 cell.xMinEnc, splitValue,
-                                 cell.yMinEnc, cell.yMaxEnc,
-                                 cell.zMinEnc, cell.zMaxEnc,
-                                 cell.splitCount+1);
-              Cell cell2 = new Cell(cell,
-                                 splitValue, cell.xMaxEnc,
-                                 cell.yMinEnc, cell.yMaxEnc,
-                                 cell.zMinEnc, cell.zMaxEnc,
-                                 cell.splitCount+1);
-              if (VERBOSE) {
-                log.println("    split cell1: " + cell1);
-                log.println("    split cell2: " + cell2);
-              }
-              queue.add(cell1);
-              queue.add(cell2);
-            }
-            break;
-
-          case 1:
-            // Split on Y:
-            {
-              int splitValue = RandomInts.randomIntBetween(random(), cell.yMinEnc, cell.yMaxEnc);
-              if (VERBOSE) {
-                log.println("    now split on y=" + splitValue);
-              }
-              Cell cell1 = new Cell(cell,
-                                 cell.xMinEnc, cell.xMaxEnc,
-                                 cell.yMinEnc, splitValue,
-                                 cell.zMinEnc, cell.zMaxEnc,
-                                 cell.splitCount+1);
-              Cell cell2 = new Cell(cell,
-                                 cell.xMinEnc, cell.xMaxEnc,
-                                 splitValue, cell.yMaxEnc,
-                                 cell.zMinEnc, cell.zMaxEnc,
-                                 cell.splitCount+1);
-              if (VERBOSE) {
-                log.println("    split cell1: " + cell1);
-                log.println("    split cell2: " + cell2);
-              }
-              queue.add(cell1);
-              queue.add(cell2);
-            }
-            break;
-
-          case 2:
-            // Split on Z:
-            {
-              int splitValue = RandomInts.randomIntBetween(random(), cell.zMinEnc, cell.zMaxEnc);
-              if (VERBOSE) {
-                log.println("    now split on z=" + splitValue);
-              }
-              Cell cell1 = new Cell(cell,
-                                 cell.xMinEnc, cell.xMaxEnc,
-                                 cell.yMinEnc, cell.yMaxEnc,
-                                 cell.zMinEnc, splitValue,
-                                 cell.splitCount+1);
-              Cell cell2 = new Cell(cell,
-                                 cell.xMinEnc, cell.xMaxEnc,
-                                 cell.yMinEnc, cell.yMaxEnc,
-                                 splitValue, cell.zMaxEnc,
-                                 cell.splitCount+1);
-              if (VERBOSE) {
-                log.println("    split cell1: " + cell1);
-                log.println("    split cell2: " + cell2);
-              }
-              queue.add(cell1);
-              queue.add(cell2);
-            }
-            break;
-          }
-        }
-      }
-
-      if (VERBOSE) {
-        log.println("  " + hits.size() + " hits");
-      }
-
-      // Done matching, now verify:
-      boolean fail = false;
-      for(int docID=0;docID<numDocs;docID++) {
-        GeoPoint point = docs[docID];
-        GeoPoint quantized = quantize(planetMax, point);
-        boolean expected = shape.isWithin(quantized);
-
-        if (expected != shape.isWithin(point)) {
-          // Quantization changed the result; skip testing this doc:
-          continue;
-        }
-
-        boolean actual = hits.contains(docID);
-        if (actual != expected) {
-          if (actual) {
-            log.println("doc=" + docID + " matched but should not");
-          } else {
-            log.println("doc=" + docID + " did not match but should");
-          }
-          log.println("  point=" + docs[docID]);
-          log.println("  quantized=" + quantize(planetMax, docs[docID]));
-          fail = true;
-        }
-      }
-
-      if (fail) {
-        System.out.print(sw.toString());
-        fail("invalid hits for shape=" + shape);
-      }
-    }
-  }
-
-  public void testRandomTiny() throws Exception {
-    // Make sure single-leaf-node case is OK:
-    doTestRandom(10);
-  }
-
-  public void testRandomMedium() throws Exception {
-    doTestRandom(10000);
-  }
-
-  @Nightly
-  public void testRandomBig() throws Exception {
-    doTestRandom(200000);
-  }
-
-  private void doTestRandom(int count) throws Exception {
-    int numPoints = atLeast(count);
-
-    if (VERBOSE) {
-      System.err.println("TEST: numPoints=" + numPoints);
-    }
-
-    double[] lats = new double[numPoints];
-    double[] lons = new double[numPoints];
-
-    boolean haveRealDoc = false;
-
-    for (int docID=0;docID<numPoints;docID++) {
-      int x = random().nextInt(20);
-      if (x == 17) {
-        // Some docs don't have a point:
-        lats[docID] = Double.NaN;
-        if (VERBOSE) {
-          System.err.println("  doc=" + docID + " is missing");
-        }
-        continue;
-      }
-
-      if (docID > 0 && x < 3 && haveRealDoc) {
-        int oldDocID;
-        while (true) {
-          oldDocID = random().nextInt(docID);
-          if (Double.isNaN(lats[oldDocID]) == false) {
-            break;
-          }
-        }
-            
-        if (x == 0) {
-          // Identical lat to old point
-          lats[docID] = lats[oldDocID];
-          lons[docID] = toRadians(randomLon());
-          if (VERBOSE) {
-            System.err.println("  doc=" + docID + " lat=" + lats[docID] + " lon=" + lons[docID] + " (same lat as doc=" + oldDocID + ")");
-          }
-        } else if (x == 1) {
-          // Identical lon to old point
-          lats[docID] = toRadians(randomLat());
-          lons[docID] = lons[oldDocID];
-          if (VERBOSE) {
-            System.err.println("  doc=" + docID + " lat=" + lats[docID] + " lon=" + lons[docID] + " (same lon as doc=" + oldDocID + ")");
-          }
-        } else {
-          assert x == 2;
-          // Fully identical point:
-          lats[docID] = lats[oldDocID];
-          lons[docID] = lons[oldDocID];
-          if (VERBOSE) {
-            System.err.println("  doc=" + docID + " lat=" + lats[docID] + " lon=" + lons[docID] + " (same lat/lon as doc=" + oldDocID + ")");
-          }
-        }
-      } else {
-        lats[docID] = toRadians(randomLat());
-        lons[docID] = toRadians(randomLon());
-        haveRealDoc = true;
-        if (VERBOSE) {
-          System.err.println("  doc=" + docID + " lat=" + lats[docID] + " lon=" + lons[docID]);
-        }
-      }
-    }
-
-    verify(lats, lons);
-  }
-
-  private static double randomLat() {
-    if (smallBBox) {
-      return 2.0 * (random().nextDouble()-0.5);
-    } else {
-      return -90 + 180.0 * random().nextDouble();
-    }
-  }
-
-  private static double randomLon() {
-    if (smallBBox) {
-      return 2.0 * (random().nextDouble()-0.5);
-    } else {
-      return -180 + 360.0 * random().nextDouble();
-    }
-  }
-
-  // Poached from Geo3dRptTest.randomShape:
-  private static GeoShape randomShape(PlanetModel planetModel) {
-    while (true) {
-      final int shapeType = random().nextInt(4);
-      switch (shapeType) {
-      case 0: {
-        // Polygons
-        final int vertexCount = random().nextInt(3) + 3;
-        final List<GeoPoint> geoPoints = new ArrayList<>();
-        while (geoPoints.size() < vertexCount) {
-          final GeoPoint gPt = new GeoPoint(planetModel, toRadians(randomLat()), toRadians(randomLon()));
-          geoPoints.add(gPt);
-        }
-        final int convexPointIndex = random().nextInt(vertexCount);       //If we get this wrong, hopefully we get IllegalArgumentException
-        try {
-          return GeoPolygonFactory.makeGeoPolygon(planetModel, geoPoints, convexPointIndex);
-        } 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
-
-        double lat = toRadians(randomLat());
-        double lon = toRadians(randomLon());
-
-        double angle;
-        if (smallBBox) {
-          angle = random().nextDouble() * Math.PI/360.0;
-        } else {
-          angle = random().nextDouble() * Math.PI/2.0;
-        }
-
-        try {
-          return GeoCircleFactory.makeGeoCircle(planetModel, lat, lon, angle);
-        } catch (IllegalArgumentException iae) {
-          // angle is too small; try again:
-          continue;
-        }
-      }
-
-      case 2: {
-        // Rectangles
-        double lat0 = toRadians(randomLat());
-        double lat1 = toRadians(randomLat());
-        if (lat1 < lat0) {
-          double x = lat0;
-          lat0 = lat1;
-          lat1 = x;
-        }
-        double lon0 = toRadians(randomLon());
-        double lon1 = toRadians(randomLon());
-        if (lon1 < lon0) {
-          double x = lon0;
-          lon0 = lon1;
-          lon1 = x;
-        }
-
-        return GeoBBoxFactory.makeGeoBBox(planetModel, lat1, lat0, lon0, lon1);
-      }
-
-      case 3: {
-        // Paths
-        final int pointCount = random().nextInt(5) + 1;
-        final double width = toRadians(random().nextInt(89)+1);
-        try {
-          final GeoPath path = new GeoPath(planetModel, width);
-          for (int i = 0; i < pointCount; i++) {
-            path.addPoint(toRadians(randomLat()), toRadians(randomLon()));
-          }
-          path.done();
-          return path;
-        } 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");
-      }
-    }
-  }
-
-  private static void verify(double[] lats, double[] lons) throws Exception {
-    IndexWriterConfig iwc = newIndexWriterConfig();
-
-    // Else we can get O(N^2) merging:
-    int mbd = iwc.getMaxBufferedDocs();
-    if (mbd != -1 && mbd < lats.length/100) {
-      iwc.setMaxBufferedDocs(lats.length/100);
-    }
-    iwc.setCodec(getCodec());
-    Directory dir;
-    if (lats.length > 100000) {
-      dir = newFSDirectory(createTempDir("TestBKDTree"));
-    } else {
-      dir = getDirectory();
-    }
-    Set<Integer> deleted = new HashSet<>();
-    // RandomIndexWriter is too slow here:
-    IndexWriter w = new IndexWriter(dir, iwc);
-    for(int id=0;id<lats.length;id++) {
-      Document doc = new Document();
-      doc.add(newStringField("id", ""+id, Field.Store.NO));
-      doc.add(new NumericDocValuesField("id", id));
-      if (Double.isNaN(lats[id]) == false) {
-        doc.add(new Geo3DPoint("point", lats[id], lons[id]));
-      }
-      w.addDocument(doc);
-      if (id > 0 && random().nextInt(100) == 42) {
-        int idToDelete = random().nextInt(id);
-        w.deleteDocuments(new Term("id", ""+idToDelete));
-        deleted.add(idToDelete);
-        if (VERBOSE) {
-          System.err.println("  delete id=" + idToDelete);
-        }
-      }
-    }
-    if (random().nextBoolean()) {
-      w.forceMerge(1);
-    }
-    final IndexReader r = DirectoryReader.open(w);
-    w.close();
-
-    // We can't wrap with "exotic" readers because the geo3d query must see the Geo3DDVFormat:
-    IndexSearcher s = newSearcher(r, false);
-
-    int numThreads = TestUtil.nextInt(random(), 2, 5);
-
-    List<Thread> threads = new ArrayList<>();
-    final int iters = atLeast(100);
-
-    final CountDownLatch startingGun = new CountDownLatch(1);
-    final AtomicBoolean failed = new AtomicBoolean();
-
-    for(int i=0;i<numThreads;i++) {
-      Thread thread = new Thread() {
-          @Override
-          public void run() {
-            try {
-              _run();
-            } catch (Exception e) {
-              failed.set(true);
-              throw new RuntimeException(e);
-            }
-          }
-
-          private void _run() throws Exception {
-            startingGun.await();
-
-            NumericDocValues docIDToID = MultiDocValues.getNumericValues(r, "id");
-
-            for (int iter=0;iter<iters && failed.get() == false;iter++) {
-
-              GeoShape shape = randomShape(PlanetModel.WGS84);
-
-              if (VERBOSE) {
-                System.err.println("\n" + Thread.currentThread() + ": TEST: iter=" + iter + " shape="+shape);
-              }
-              
-              Query query = Geo3DPoint.newShapeQuery("point", shape);
-
-              if (VERBOSE) {
-                System.err.println("  using query: " + query);
-              }
-
-              final FixedBitSet hits = new FixedBitSet(r.maxDoc());
-
-              s.search(query, new SimpleCollector() {
-
-                  private int docBase;
-
-                  @Override
-                  public boolean needsScores() {
-                    return false;
-                  }
-
-                  @Override
-                  protected void doSetNextReader(LeafReaderContext context) throws IOException {
-                    docBase = context.docBase;
-                  }
-
-                  @Override
-                  public void collect(int doc) {
-                    hits.set(docBase+doc);
-                  }
-                });
-
-              if (VERBOSE) {
-                System.err.println("  hitCount: " + hits.cardinality());
-              }
-      
-              for(int docID=0;docID<r.maxDoc();docID++) {
-                int id = (int) docIDToID.get(docID);
-                if (Double.isNaN(lats[id]) == false) {
-
-                  // Accurate point:
-                  GeoPoint point1 = new GeoPoint(PlanetModel.WGS84, lats[id], lons[id]);
-
-                  // Quantized point (32 bits per dim):
-                  GeoPoint point2 = quantize(PlanetModel.WGS84.getMaximumMagnitude(), point1);
-
-                  if (shape.isWithin(point1) != shape.isWithin(point2)) {
-                    if (VERBOSE) {
-                      System.out.println("  skip checking docID=" + docID + " quantization changed the expected result from " + shape.isWithin(point1) + " to " + shape.isWithin(point2));
-                    }
-                    continue;
-                  }
-
-                  boolean expected = ((deleted.contains(id) == false) && shape.isWithin(point2));
-                  if (hits.get(docID) != expected) {
-                    fail(Thread.currentThread().getName() + ": iter=" + iter + " id=" + id + " docID=" + docID + " lat=" + lats[id] + " lon=" + lons[id] + " expected " + expected + " but got: " + hits.get(docID) + " deleted?=" + deleted.contains(id) + "\n  point1=" + point1 + ", iswithin="+shape.isWithin(point1)+"\n  point2=" + point2 + ", iswithin="+shape.isWithin(point2) + "\n  query=" + query);
-                  }
-                } else {
-                  assertFalse(hits.get(docID));
-                }
-
-              }
-            }
-          }
-        };
-      thread.setName("T" + i);
-      thread.start();
-      threads.add(thread);
-    }
-    startingGun.countDown();
-    for(Thread thread : threads) {
-      thread.join();
-    }
-    IOUtils.close(r, dir);
-  }
-
-  public void testToString() {
-    Geo3DPoint point = new Geo3DPoint("point", toRadians(44.244272), toRadians(7.769736));
-    assertEquals("Geo3DPoint <point: x=0.9248467864160119 y=0.06280434265368656 z=0.37682349005486243>", point.toString());
-  }
-
-  public void testShapeQueryToString() {
-    assertEquals("PointInGeo3DShapeQuery: field=point: Shape: GeoStandardCircle: {planetmodel=PlanetModel.WGS84, center=[lat=0.3861041107739683, lon=0.06780373760536706], radius=0.1(5.729577951308232)}",
-                 Geo3DPoint.newShapeQuery("point", GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84, toRadians(44.244272), toRadians(7.769736), 0.1)).toString());
-  }
-
-  private static Directory getDirectory() {     
-    return newDirectory();
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/test/org/apache/lucene/geo3d/XYZSolidTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/XYZSolidTest.java b/lucene/spatial3d/src/test/org/apache/lucene/geo3d/XYZSolidTest.java
deleted file mode 100644
index 876a525..0000000
--- a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/XYZSolidTest.java
+++ /dev/null
@@ -1,220 +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.geo3d;
-
-import org.apache.lucene.util.LuceneTestCase;
-import org.junit.Test;
-
-public class XYZSolidTest extends LuceneTestCase {
-
-  @Test
-  public void testNonDegenerateRelationships() {
-    XYZSolid s;
-    GeoShape shape;
-    // Something bigger than the world
-    s = new StandardXYZSolid(PlanetModel.SPHERE, -2.0, 2.0, -2.0, 2.0, -2.0, 2.0);
-    // Any shape, except whole world, should be within.
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.WITHIN, s.getRelationship(shape));
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    // An XYZSolid represents a surface shape, which when larger than the world is in fact
-    // the entire world, so it should overlap the world.
-    assertEquals(GeoArea.OVERLAPS, s.getRelationship(shape));
-
-    // Something overlapping the world on only one side
-    s = new StandardXYZSolid(PlanetModel.SPHERE, -2.0, 0.0, -2.0, 2.0, -2.0, 2.0);
-    // Some things should be disjoint...
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, s.getRelationship(shape));
-    // And, some things should be within... 
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI, 0.1);
-    assertEquals(GeoArea.WITHIN, s.getRelationship(shape));
-    // And, some things should overlap.
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI * 0.5, 0.1);
-    assertEquals(GeoArea.OVERLAPS, s.getRelationship(shape));
-
-    // Partial world should be contained by GeoWorld object...
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.CONTAINS, s.getRelationship(shape));
-    
-    // Something inside the world
-    s = new StandardXYZSolid(PlanetModel.SPHERE, -0.1, 0.1, -0.1, 0.1, -0.1, 0.1);
-    // All shapes should be disjoint
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, s.getRelationship(shape));
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.DISJOINT, s.getRelationship(shape));
-    
-  }
-
-  @Test
-  public void testDegenerateRelationships() {
-    GeoArea solid;
-    GeoShape shape;
-    
-    // Basic test of the factory method - non-degenerate
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, -2.0, 2.0, -2.0, 2.0, -2.0, 2.0);
-    // Any shape, except whole world, should be within.
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.WITHIN, solid.getRelationship(shape));
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    // An XYZSolid represents a surface shape, which when larger than the world is in fact
-    // the entire world, so it should overlap the world.
-    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
-
-    // Build a degenerate point, not on sphere
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
-    // disjoint with everything?
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-
-    // Build a degenerate point that IS on the sphere
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0);
-    // inside everything that it touches?
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-
-    // Build a shape degenerate in (x,y), which has no points on sphere
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, 0.0, 0.0, -0.1, 0.1);
-    // disjoint with everything?
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-
-    // Build a shape degenerate in (x,y) which has one point on sphere
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, 0.0, 0.0, -0.1, 1.1);
-    // inside everything that it touches?
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, Math.PI * 0.5, 0.0, 0.1);
-    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-
-    // Build a shape degenerate in (x,y) which has two points on sphere
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, 0.0, 0.0, -1.1, 1.1);
-    // inside everything that it touches?
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, Math.PI * 0.5, 0.0, 0.1);
-    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0, 0.1);
-    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
-    
-    // Build a shape degenerate in (x,z), which has no points on sphere
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, -0.1, 0.1, 0.0, 0.0);
-    // disjoint with everything?
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-
-    // Build a shape degenerate in (x,z) which has one point on sphere
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, -0.1, 1.1, 0.0, 0.0);
-    // inside everything that it touches?
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI * 0.5, 0.1);
-    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, -Math.PI * 0.5, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-
-    // Build a shape degenerate in (x,y) which has two points on sphere
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, -1.1, 1.1, 0.0, 0.0);
-    // inside everything that it touches?
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI * 0.5, 0.1);
-    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, -Math.PI * 0.5, 0.1);
-    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
-
-    // MHL for y-z check
-    
-    // Build a shape that is degenerate in x, which has zero points intersecting sphere
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, -0.1, 0.1, -0.1, 0.1);
-    // disjoint with everything?
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-
-    // Build a shape that is degenerate in x, which has zero points intersecting sphere, second variation
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, -0.1, 0.1, 1.1, 1.2);
-    // disjoint with everything?
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-
-    // Build a shape that is disjoint in X but intersects sphere in a complete circle
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, -1.1, 1.1, -1.1, 1.1);
-    // inside everything that it touches?
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI * 0.5, 0.1);
-    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, -Math.PI * 0.5, 0.1);
-    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, Math.PI * 0.5, 0.0, 0.1);
-    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0, 0.1);
-    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
-
-    // Build a shape that is disjoint in X but intersects sphere in a half circle in Y
-    solid = GeoAreaFactory.makeGeoArea(PlanetModel.SPHERE, 0.0, 0.0, 0.0, 1.1, -1.1, 1.1);
-    // inside everything that it touches?
-    shape = new GeoWorld(PlanetModel.SPHERE);
-    assertEquals(GeoArea.CONTAINS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, Math.PI * 0.5, 0.1);
-    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, -Math.PI * 0.5, 0.1);
-    assertEquals(GeoArea.DISJOINT, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, Math.PI * 0.5, 0.0, 0.1);
-    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
-    shape = new GeoStandardCircle(PlanetModel.SPHERE, -Math.PI * 0.5, 0.0, 0.1);
-    assertEquals(GeoArea.OVERLAPS, solid.getRelationship(shape));
-
-    // MHL for degenerate Y
-    // MHL for degenerate Z
-    
-  }
-  
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/TestGeo3DPoint.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/TestGeo3DPoint.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/TestGeo3DPoint.java
new file mode 100644
index 0000000..a4d8ed1
--- /dev/null
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/TestGeo3DPoint.java
@@ -0,0 +1,810 @@
+/*
+ * 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.spatial3d;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.lucene.codecs.Codec;
+import org.apache.lucene.codecs.FilterCodec;
+import org.apache.lucene.codecs.PointsFormat;
+import org.apache.lucene.codecs.PointsReader;
+import org.apache.lucene.codecs.PointsWriter;
+import org.apache.lucene.codecs.lucene60.Lucene60PointsReader;
+import org.apache.lucene.codecs.lucene60.Lucene60PointsWriter;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.NumericDocValuesField;
+import org.apache.lucene.spatial3d.geom.GeoArea;
+import org.apache.lucene.spatial3d.geom.GeoAreaFactory;
+import org.apache.lucene.spatial3d.geom.GeoBBoxFactory;
+import org.apache.lucene.spatial3d.geom.GeoCircleFactory;
+import org.apache.lucene.spatial3d.geom.GeoPath;
+import org.apache.lucene.spatial3d.geom.GeoPoint;
+import org.apache.lucene.spatial3d.geom.GeoPolygonFactory;
+import org.apache.lucene.spatial3d.geom.GeoShape;
+import org.apache.lucene.spatial3d.geom.PlanetModel;
+import org.apache.lucene.spatial3d.geom.XYZBounds;
+import org.apache.lucene.index.DirectoryReader;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.IndexWriterConfig;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.MultiDocValues;
+import org.apache.lucene.index.NumericDocValues;
+import org.apache.lucene.index.SegmentReadState;
+import org.apache.lucene.index.SegmentWriteState;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.SimpleCollector;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.util.FixedBitSet;
+import org.apache.lucene.util.IOUtils;
+import org.apache.lucene.util.LuceneTestCase;
+import org.apache.lucene.util.TestUtil;
+import org.junit.BeforeClass;
+
+import com.carrotsearch.randomizedtesting.generators.RandomInts;
+
+public class TestGeo3DPoint extends LuceneTestCase {
+
+  private static boolean smallBBox;
+  
+  @BeforeClass
+  public static void beforeClass() {
+    smallBBox = random().nextBoolean();
+    if (VERBOSE) {
+      System.err.println("TEST: smallBBox=" + smallBBox);
+    }
+  }
+
+  private static Codec getCodec() {
+    if (Codec.getDefault().getName().equals("Lucene60")) {
+      int maxPointsInLeafNode = TestUtil.nextInt(random(), 16, 2048);
+      double maxMBSortInHeap = 3.0 + (3*random().nextDouble());
+      if (VERBOSE) {
+        System.out.println("TEST: using Lucene60PointsFormat with maxPointsInLeafNode=" + maxPointsInLeafNode + " and maxMBSortInHeap=" + maxMBSortInHeap);
+      }
+
+      return new FilterCodec("Lucene60", Codec.getDefault()) {
+        @Override
+        public PointsFormat pointsFormat() {
+          return new PointsFormat() {
+            @Override
+            public PointsWriter fieldsWriter(SegmentWriteState writeState) throws IOException {
+              return new Lucene60PointsWriter(writeState, maxPointsInLeafNode, maxMBSortInHeap);
+            }
+
+            @Override
+            public PointsReader fieldsReader(SegmentReadState readState) throws IOException {
+              return new Lucene60PointsReader(readState);
+            }
+          };
+        }
+      };
+    } else {
+      return Codec.getDefault();
+    }
+  }
+
+  public void testBasic() throws Exception {
+    Directory dir = getDirectory();
+    IndexWriterConfig iwc = newIndexWriterConfig();
+    iwc.setCodec(getCodec());
+    IndexWriter w = new IndexWriter(dir, iwc);
+    Document doc = new Document();
+    doc.add(new Geo3DPoint("field", toRadians(50.7345267), toRadians(-97.5303555)));
+    w.addDocument(doc);
+    IndexReader r = DirectoryReader.open(w);
+    // We can't wrap with "exotic" readers because the query must see the BKD3DDVFormat:
+    IndexSearcher s = newSearcher(r, false);
+    assertEquals(1, s.search(Geo3DPoint.newShapeQuery("field",
+                                                      GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84, toRadians(50), toRadians(-97), Math.PI/180.)), 1).totalHits);
+    w.close();
+    r.close();
+    dir.close();
+  }
+
+  private static double toRadians(double degrees) {
+    return Math.PI*(degrees/360.0);
+  }
+
+  private static PlanetModel getPlanetModel() {
+    if (random().nextBoolean()) {
+      // Use one of the earth models:
+      if (random().nextBoolean()) {
+        return PlanetModel.WGS84;
+      } else {
+        return PlanetModel.SPHERE;
+      }
+    } else {
+      // Make a randomly squashed planet:
+      double oblateness = random().nextDouble() * 0.5 - 0.25;
+      return new PlanetModel(1.0 + oblateness, 1.0 - oblateness);
+    }
+  }
+
+  private static class Cell {
+    static int nextCellID;
+
+    final Cell parent;
+    final int cellID;
+    final int xMinEnc, xMaxEnc;
+    final int yMinEnc, yMaxEnc;
+    final int zMinEnc, zMaxEnc;
+    final int splitCount;
+
+    public Cell(Cell parent,
+                int xMinEnc, int xMaxEnc,
+                int yMinEnc, int yMaxEnc,
+                int zMinEnc, int zMaxEnc,
+                int splitCount) {
+      this.parent = parent;
+      this.xMinEnc = xMinEnc;
+      this.xMaxEnc = xMaxEnc;
+      this.yMinEnc = yMinEnc;
+      this.yMaxEnc = yMaxEnc;
+      this.zMinEnc = zMinEnc;
+      this.zMaxEnc = zMaxEnc;
+      this.cellID = nextCellID++;
+      this.splitCount = splitCount;
+    }
+
+    /** Returns true if the quantized point lies within this cell, inclusive on all bounds. */
+    public boolean contains(double planetMax, GeoPoint point) {
+      int docX = Geo3DUtil.encodeValue(planetMax, point.x);
+      int docY = Geo3DUtil.encodeValue(planetMax, point.y);
+      int docZ = Geo3DUtil.encodeValue(planetMax, point.z);
+
+      return docX >= xMinEnc && docX <= xMaxEnc &&
+        docY >= yMinEnc && docY <= yMaxEnc && 
+        docZ >= zMinEnc && docZ <= zMaxEnc;
+    }
+
+    @Override
+    public String toString() {
+      return "cell=" + cellID + (parent == null ? "" : " parentCellID=" + parent.cellID) + " x: " + xMinEnc + " TO " + xMaxEnc + ", y: " + yMinEnc + " TO " + yMaxEnc + ", z: " + zMinEnc + " TO " + zMaxEnc + ", splits: " + splitCount;
+    }
+  }
+
+  private static GeoPoint quantize(double planetMax, GeoPoint point) {
+    return new GeoPoint(Geo3DUtil.decodeValueCenter(planetMax, Geo3DUtil.encodeValue(planetMax, point.x)),
+                        Geo3DUtil.decodeValueCenter(planetMax, Geo3DUtil.encodeValue(planetMax, point.y)),
+                        Geo3DUtil.decodeValueCenter(planetMax, Geo3DUtil.encodeValue(planetMax, point.z)));
+  }
+
+  /** Tests consistency of GeoArea.getRelationship vs GeoShape.isWithin */
+  public void testGeo3DRelations() throws Exception {
+
+    PlanetModel planetModel = getPlanetModel();
+
+    int numDocs = atLeast(1000);
+    if (VERBOSE) {
+      System.out.println("TEST: " + numDocs + " docs");
+    }
+
+    GeoPoint[] docs = new GeoPoint[numDocs];
+    for(int docID=0;docID<numDocs;docID++) {
+      docs[docID] = new GeoPoint(planetModel, toRadians(randomLat()), toRadians(randomLon()));
+      if (VERBOSE) {
+        System.out.println("  doc=" + docID + ": " + docs[docID]);
+      }
+    }
+
+    double planetMax = planetModel.getMaximumMagnitude();
+
+    int iters = atLeast(10);
+
+    int recurseDepth = RandomInts.randomIntBetween(random(), 5, 15);
+
+    iters = atLeast(50);
+    
+    for(int iter=0;iter<iters;iter++) {
+      GeoShape shape = randomShape(planetModel);
+
+      StringWriter sw = new StringWriter();
+      PrintWriter log = new PrintWriter(sw, true);
+
+      if (VERBOSE) {
+        log.println("TEST: iter=" + iter + " shape=" + shape);
+      }
+
+      XYZBounds bounds = new XYZBounds();
+      shape.getBounds(bounds);
+
+      // Start with the root cell that fully contains the shape:
+      Cell root = new Cell(null,
+                           Geo3DUtil.encodeValueLenient(planetMax, bounds.getMinimumX()),
+                           Geo3DUtil.encodeValueLenient(planetMax, bounds.getMaximumX()),
+                           Geo3DUtil.encodeValueLenient(planetMax, bounds.getMinimumY()),
+                           Geo3DUtil.encodeValueLenient(planetMax, bounds.getMaximumY()),
+                           Geo3DUtil.encodeValueLenient(planetMax, bounds.getMinimumZ()),
+                           Geo3DUtil.encodeValueLenient(planetMax, bounds.getMaximumZ()),
+                           0);
+
+      if (VERBOSE) {
+        log.println("  root cell: " + root);
+      }
+
+      List<Cell> queue = new ArrayList<>();
+      queue.add(root);
+      Set<Integer> hits = new HashSet<>();
+
+      while (queue.size() > 0) {
+        Cell cell = queue.get(queue.size()-1);
+        queue.remove(queue.size()-1);
+        if (VERBOSE) {
+          log.println("  cycle: " + cell + " queue.size()=" + queue.size());
+        }
+
+        if (random().nextInt(10) == 7 || cell.splitCount > recurseDepth) {
+          if (VERBOSE) {
+            log.println("    leaf");
+          }
+          // Leaf cell: brute force check all docs that fall within this cell:
+          for(int docID=0;docID<numDocs;docID++) {
+            GeoPoint point = docs[docID];
+            if (cell.contains(planetMax, point)) {
+              if (shape.isWithin(quantize(planetMax, point))) {
+                if (VERBOSE) {
+                  log.println("    check doc=" + docID + ": match!");
+                }
+                hits.add(docID);
+              } else {
+                if (VERBOSE) {
+                  log.println("    check doc=" + docID + ": no match");
+                }
+              }
+            }
+          }
+        } else {
+          
+          GeoArea xyzSolid = GeoAreaFactory.makeGeoArea(planetModel,
+                                                        Geo3DUtil.decodeValueMin(planetMax, cell.xMinEnc), Geo3DUtil.decodeValueMax(planetMax, cell.xMaxEnc),
+                                                        Geo3DUtil.decodeValueMin(planetMax, cell.yMinEnc), Geo3DUtil.decodeValueMax(planetMax, cell.yMaxEnc),
+                                                        Geo3DUtil.decodeValueMin(planetMax, cell.zMinEnc), Geo3DUtil.decodeValueMax(planetMax, cell.zMaxEnc));
+
+          if (VERBOSE) {
+            log.println("    minx="+Geo3DUtil.decodeValueMin(planetMax, cell.xMinEnc)+" maxx="+Geo3DUtil.decodeValueMax(planetMax, cell.xMaxEnc)+
+              " miny="+Geo3DUtil.decodeValueMin(planetMax, cell.yMinEnc)+" maxy="+Geo3DUtil.decodeValueMax(planetMax, cell.yMaxEnc)+
+              " minz="+Geo3DUtil.decodeValueMin(planetMax, cell.zMinEnc)+" maxz="+Geo3DUtil.decodeValueMax(planetMax, cell.zMaxEnc));
+          }
+
+          switch (xyzSolid.getRelationship(shape)) {          
+          case GeoArea.CONTAINS:
+            // Shape fully contains the cell: blindly add all docs in this cell:
+            if (VERBOSE) {
+              log.println("    GeoArea.CONTAINS: now addAll");
+            }
+            for(int docID=0;docID<numDocs;docID++) {
+              if (cell.contains(planetMax, docs[docID])) {
+                if (VERBOSE) {
+                  log.println("    addAll doc=" + docID);
+                }
+                hits.add(docID);
+              }
+            }
+            continue;
+          case GeoArea.OVERLAPS:
+            if (VERBOSE) {
+              log.println("    GeoArea.OVERLAPS: keep splitting");
+            }
+            // They do overlap but neither contains the other:
+            //log.println("    crosses1");
+            break;
+          case GeoArea.WITHIN:
+            if (VERBOSE) {
+              log.println("    GeoArea.WITHIN: keep splitting");
+            }
+            // Cell fully contains the shape:
+            //log.println("    crosses2");
+            break;
+          case GeoArea.DISJOINT:
+            // They do not overlap at all: don't recurse on this cell
+            //log.println("    outside");
+            if (VERBOSE) {
+              log.println("    GeoArea.DISJOINT: drop this cell");
+              for(int docID=0;docID<numDocs;docID++) {
+                if (cell.contains(planetMax, docs[docID])) {
+                  if (VERBOSE) {
+                    log.println("    skip doc=" + docID);
+                  }
+                }
+              }
+            }
+            continue;
+          default:
+            assert false;
+          }
+
+          // Randomly split:
+          switch(random().nextInt(3)) {
+
+          case 0:
+            // Split on X:
+            {
+              int splitValue = RandomInts.randomIntBetween(random(), cell.xMinEnc, cell.xMaxEnc);
+              if (VERBOSE) {
+                log.println("    now split on x=" + splitValue);
+              }
+              Cell cell1 = new Cell(cell,
+                                 cell.xMinEnc, splitValue,
+                                 cell.yMinEnc, cell.yMaxEnc,
+                                 cell.zMinEnc, cell.zMaxEnc,
+                                 cell.splitCount+1);
+              Cell cell2 = new Cell(cell,
+                                 splitValue, cell.xMaxEnc,
+                                 cell.yMinEnc, cell.yMaxEnc,
+                                 cell.zMinEnc, cell.zMaxEnc,
+                                 cell.splitCount+1);
+              if (VERBOSE) {
+                log.println("    split cell1: " + cell1);
+                log.println("    split cell2: " + cell2);
+              }
+              queue.add(cell1);
+              queue.add(cell2);
+            }
+            break;
+
+          case 1:
+            // Split on Y:
+            {
+              int splitValue = RandomInts.randomIntBetween(random(), cell.yMinEnc, cell.yMaxEnc);
+              if (VERBOSE) {
+                log.println("    now split on y=" + splitValue);
+              }
+              Cell cell1 = new Cell(cell,
+                                 cell.xMinEnc, cell.xMaxEnc,
+                                 cell.yMinEnc, splitValue,
+                                 cell.zMinEnc, cell.zMaxEnc,
+                                 cell.splitCount+1);
+              Cell cell2 = new Cell(cell,
+                                 cell.xMinEnc, cell.xMaxEnc,
+                                 splitValue, cell.yMaxEnc,
+                                 cell.zMinEnc, cell.zMaxEnc,
+                                 cell.splitCount+1);
+              if (VERBOSE) {
+                log.println("    split cell1: " + cell1);
+                log.println("    split cell2: " + cell2);
+              }
+              queue.add(cell1);
+              queue.add(cell2);
+            }
+            break;
+
+          case 2:
+            // Split on Z:
+            {
+              int splitValue = RandomInts.randomIntBetween(random(), cell.zMinEnc, cell.zMaxEnc);
+              if (VERBOSE) {
+                log.println("    now split on z=" + splitValue);
+              }
+              Cell cell1 = new Cell(cell,
+                                 cell.xMinEnc, cell.xMaxEnc,
+                                 cell.yMinEnc, cell.yMaxEnc,
+                                 cell.zMinEnc, splitValue,
+                                 cell.splitCount+1);
+              Cell cell2 = new Cell(cell,
+                                 cell.xMinEnc, cell.xMaxEnc,
+                                 cell.yMinEnc, cell.yMaxEnc,
+                                 splitValue, cell.zMaxEnc,
+                                 cell.splitCount+1);
+              if (VERBOSE) {
+                log.println("    split cell1: " + cell1);
+                log.println("    split cell2: " + cell2);
+              }
+              queue.add(cell1);
+              queue.add(cell2);
+            }
+            break;
+          }
+        }
+      }
+
+      if (VERBOSE) {
+        log.println("  " + hits.size() + " hits");
+      }
+
+      // Done matching, now verify:
+      boolean fail = false;
+      for(int docID=0;docID<numDocs;docID++) {
+        GeoPoint point = docs[docID];
+        GeoPoint quantized = quantize(planetMax, point);
+        boolean expected = shape.isWithin(quantized);
+
+        if (expected != shape.isWithin(point)) {
+          // Quantization changed the result; skip testing this doc:
+          continue;
+        }
+
+        boolean actual = hits.contains(docID);
+        if (actual != expected) {
+          if (actual) {
+            log.println("doc=" + docID + " matched but should not");
+          } else {
+            log.println("doc=" + docID + " did not match but should");
+          }
+          log.println("  point=" + docs[docID]);
+          log.println("  quantized=" + quantize(planetMax, docs[docID]));
+          fail = true;
+        }
+      }
+
+      if (fail) {
+        System.out.print(sw.toString());
+        fail("invalid hits for shape=" + shape);
+      }
+    }
+  }
+
+  public void testRandomTiny() throws Exception {
+    // Make sure single-leaf-node case is OK:
+    doTestRandom(10);
+  }
+
+  public void testRandomMedium() throws Exception {
+    doTestRandom(10000);
+  }
+
+  @Nightly
+  public void testRandomBig() throws Exception {
+    doTestRandom(200000);
+  }
+
+  private void doTestRandom(int count) throws Exception {
+    int numPoints = atLeast(count);
+
+    if (VERBOSE) {
+      System.err.println("TEST: numPoints=" + numPoints);
+    }
+
+    double[] lats = new double[numPoints];
+    double[] lons = new double[numPoints];
+
+    boolean haveRealDoc = false;
+
+    for (int docID=0;docID<numPoints;docID++) {
+      int x = random().nextInt(20);
+      if (x == 17) {
+        // Some docs don't have a point:
+        lats[docID] = Double.NaN;
+        if (VERBOSE) {
+          System.err.println("  doc=" + docID + " is missing");
+        }
+        continue;
+      }
+
+      if (docID > 0 && x < 3 && haveRealDoc) {
+        int oldDocID;
+        while (true) {
+          oldDocID = random().nextInt(docID);
+          if (Double.isNaN(lats[oldDocID]) == false) {
+            break;
+          }
+        }
+            
+        if (x == 0) {
+          // Identical lat to old point
+          lats[docID] = lats[oldDocID];
+          lons[docID] = toRadians(randomLon());
+          if (VERBOSE) {
+            System.err.println("  doc=" + docID + " lat=" + lats[docID] + " lon=" + lons[docID] + " (same lat as doc=" + oldDocID + ")");
+          }
+        } else if (x == 1) {
+          // Identical lon to old point
+          lats[docID] = toRadians(randomLat());
+          lons[docID] = lons[oldDocID];
+          if (VERBOSE) {
+            System.err.println("  doc=" + docID + " lat=" + lats[docID] + " lon=" + lons[docID] + " (same lon as doc=" + oldDocID + ")");
+          }
+        } else {
+          assert x == 2;
+          // Fully identical point:
+          lats[docID] = lats[oldDocID];
+          lons[docID] = lons[oldDocID];
+          if (VERBOSE) {
+            System.err.println("  doc=" + docID + " lat=" + lats[docID] + " lon=" + lons[docID] + " (same lat/lon as doc=" + oldDocID + ")");
+          }
+        }
+      } else {
+        lats[docID] = toRadians(randomLat());
+        lons[docID] = toRadians(randomLon());
+        haveRealDoc = true;
+        if (VERBOSE) {
+          System.err.println("  doc=" + docID + " lat=" + lats[docID] + " lon=" + lons[docID]);
+        }
+      }
+    }
+
+    verify(lats, lons);
+  }
+
+  private static double randomLat() {
+    if (smallBBox) {
+      return 2.0 * (random().nextDouble()-0.5);
+    } else {
+      return -90 + 180.0 * random().nextDouble();
+    }
+  }
+
+  private static double randomLon() {
+    if (smallBBox) {
+      return 2.0 * (random().nextDouble()-0.5);
+    } else {
+      return -180 + 360.0 * random().nextDouble();
+    }
+  }
+
+  // Poached from Geo3dRptTest.randomShape:
+  private static GeoShape randomShape(PlanetModel planetModel) {
+    while (true) {
+      final int shapeType = random().nextInt(4);
+      switch (shapeType) {
+      case 0: {
+        // Polygons
+        final int vertexCount = random().nextInt(3) + 3;
+        final List<GeoPoint> geoPoints = new ArrayList<>();
+        while (geoPoints.size() < vertexCount) {
+          final GeoPoint gPt = new GeoPoint(planetModel, toRadians(randomLat()), toRadians(randomLon()));
+          geoPoints.add(gPt);
+        }
+        final int convexPointIndex = random().nextInt(vertexCount);       //If we get this wrong, hopefully we get IllegalArgumentException
+        try {
+          return GeoPolygonFactory.makeGeoPolygon(planetModel, geoPoints, convexPointIndex);
+        } 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
+
+        double lat = toRadians(randomLat());
+        double lon = toRadians(randomLon());
+
+        double angle;
+        if (smallBBox) {
+          angle = random().nextDouble() * Math.PI/360.0;
+        } else {
+          angle = random().nextDouble() * Math.PI/2.0;
+        }
+
+        try {
+          return GeoCircleFactory.makeGeoCircle(planetModel, lat, lon, angle);
+        } catch (IllegalArgumentException iae) {
+          // angle is too small; try again:
+          continue;
+        }
+      }
+
+      case 2: {
+        // Rectangles
+        double lat0 = toRadians(randomLat());
+        double lat1 = toRadians(randomLat());
+        if (lat1 < lat0) {
+          double x = lat0;
+          lat0 = lat1;
+          lat1 = x;
+        }
+        double lon0 = toRadians(randomLon());
+        double lon1 = toRadians(randomLon());
+        if (lon1 < lon0) {
+          double x = lon0;
+          lon0 = lon1;
+          lon1 = x;
+        }
+
+        return GeoBBoxFactory.makeGeoBBox(planetModel, lat1, lat0, lon0, lon1);
+      }
+
+      case 3: {
+        // Paths
+        final int pointCount = random().nextInt(5) + 1;
+        final double width = toRadians(random().nextInt(89)+1);
+        try {
+          final GeoPath path = new GeoPath(planetModel, width);
+          for (int i = 0; i < pointCount; i++) {
+            path.addPoint(toRadians(randomLat()), toRadians(randomLon()));
+          }
+          path.done();
+          return path;
+        } 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");
+      }
+    }
+  }
+
+  private static void verify(double[] lats, double[] lons) throws Exception {
+    IndexWriterConfig iwc = newIndexWriterConfig();
+
+    // Else we can get O(N^2) merging:
+    int mbd = iwc.getMaxBufferedDocs();
+    if (mbd != -1 && mbd < lats.length/100) {
+      iwc.setMaxBufferedDocs(lats.length/100);
+    }
+    iwc.setCodec(getCodec());
+    Directory dir;
+    if (lats.length > 100000) {
+      dir = newFSDirectory(createTempDir("TestBKDTree"));
+    } else {
+      dir = getDirectory();
+    }
+    Set<Integer> deleted = new HashSet<>();
+    // RandomIndexWriter is too slow here:
+    IndexWriter w = new IndexWriter(dir, iwc);
+    for(int id=0;id<lats.length;id++) {
+      Document doc = new Document();
+      doc.add(newStringField("id", ""+id, Field.Store.NO));
+      doc.add(new NumericDocValuesField("id", id));
+      if (Double.isNaN(lats[id]) == false) {
+        doc.add(new Geo3DPoint("point", lats[id], lons[id]));
+      }
+      w.addDocument(doc);
+      if (id > 0 && random().nextInt(100) == 42) {
+        int idToDelete = random().nextInt(id);
+        w.deleteDocuments(new Term("id", ""+idToDelete));
+        deleted.add(idToDelete);
+        if (VERBOSE) {
+          System.err.println("  delete id=" + idToDelete);
+        }
+      }
+    }
+    if (random().nextBoolean()) {
+      w.forceMerge(1);
+    }
+    final IndexReader r = DirectoryReader.open(w);
+    w.close();
+
+    // We can't wrap with "exotic" readers because the geo3d query must see the Geo3DDVFormat:
+    IndexSearcher s = newSearcher(r, false);
+
+    int numThreads = TestUtil.nextInt(random(), 2, 5);
+
+    List<Thread> threads = new ArrayList<>();
+    final int iters = atLeast(100);
+
+    final CountDownLatch startingGun = new CountDownLatch(1);
+    final AtomicBoolean failed = new AtomicBoolean();
+
+    for(int i=0;i<numThreads;i++) {
+      Thread thread = new Thread() {
+          @Override
+          public void run() {
+            try {
+              _run();
+            } catch (Exception e) {
+              failed.set(true);
+              throw new RuntimeException(e);
+            }
+          }
+
+          private void _run() throws Exception {
+            startingGun.await();
+
+            NumericDocValues docIDToID = MultiDocValues.getNumericValues(r, "id");
+
+            for (int iter=0;iter<iters && failed.get() == false;iter++) {
+
+              GeoShape shape = randomShape(PlanetModel.WGS84);
+
+              if (VERBOSE) {
+                System.err.println("\n" + Thread.currentThread() + ": TEST: iter=" + iter + " shape="+shape);
+              }
+              
+              Query query = Geo3DPoint.newShapeQuery("point", shape);
+
+              if (VERBOSE) {
+                System.err.println("  using query: " + query);
+              }
+
+              final FixedBitSet hits = new FixedBitSet(r.maxDoc());
+
+              s.search(query, new SimpleCollector() {
+
+                  private int docBase;
+
+                  @Override
+                  public boolean needsScores() {
+                    return false;
+                  }
+
+                  @Override
+                  protected void doSetNextReader(LeafReaderContext context) throws IOException {
+                    docBase = context.docBase;
+                  }
+
+                  @Override
+                  public void collect(int doc) {
+                    hits.set(docBase+doc);
+                  }
+                });
+
+              if (VERBOSE) {
+                System.err.println("  hitCount: " + hits.cardinality());
+              }
+      
+              for(int docID=0;docID<r.maxDoc();docID++) {
+                int id = (int) docIDToID.get(docID);
+                if (Double.isNaN(lats[id]) == false) {
+
+                  // Accurate point:
+                  GeoPoint point1 = new GeoPoint(PlanetModel.WGS84, lats[id], lons[id]);
+
+                  // Quantized point (32 bits per dim):
+                  GeoPoint point2 = quantize(PlanetModel.WGS84.getMaximumMagnitude(), point1);
+
+                  if (shape.isWithin(point1) != shape.isWithin(point2)) {
+                    if (VERBOSE) {
+                      System.out.println("  skip checking docID=" + docID + " quantization changed the expected result from " + shape.isWithin(point1) + " to " + shape.isWithin(point2));
+                    }
+                    continue;
+                  }
+
+                  boolean expected = ((deleted.contains(id) == false) && shape.isWithin(point2));
+                  if (hits.get(docID) != expected) {
+                    fail(Thread.currentThread().getName() + ": iter=" + iter + " id=" + id + " docID=" + docID + " lat=" + lats[id] + " lon=" + lons[id] + " expected " + expected + " but got: " + hits.get(docID) + " deleted?=" + deleted.contains(id) + "\n  point1=" + point1 + ", iswithin="+shape.isWithin(point1)+"\n  point2=" + point2 + ", iswithin="+shape.isWithin(point2) + "\n  query=" + query);
+                  }
+                } else {
+                  assertFalse(hits.get(docID));
+                }
+
+              }
+            }
+          }
+        };
+      thread.setName("T" + i);
+      thread.start();
+      threads.add(thread);
+    }
+    startingGun.countDown();
+    for(Thread thread : threads) {
+      thread.join();
+    }
+    IOUtils.close(r, dir);
+  }
+
+  public void testToString() {
+    Geo3DPoint point = new Geo3DPoint("point", toRadians(44.244272), toRadians(7.769736));
+    assertEquals("Geo3DPoint <point: x=0.9248467864160119 y=0.06280434265368656 z=0.37682349005486243>", point.toString());
+  }
+
+  public void testShapeQueryToString() {
+    assertEquals("PointInGeo3DShapeQuery: field=point: Shape: GeoStandardCircle: {planetmodel=PlanetModel.WGS84, center=[lat=0.3861041107739683, lon=0.06780373760536706], radius=0.1(5.729577951308232)}",
+                 Geo3DPoint.newShapeQuery("point", GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84, toRadians(44.244272), toRadians(7.769736), 0.1)).toString());
+  }
+
+  private static Directory getDirectory() {     
+    return newDirectory();
+  }
+}


[11/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 0093e26)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/PlanetModel.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/PlanetModel.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/PlanetModel.java
deleted file mode 100644
index 395fa15..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/PlanetModel.java
+++ /dev/null
@@ -1,277 +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.geo3d;
-
-/**
- * Holds mathematical constants associated with the model of a planet.
- * @lucene.experimental
- */
-public class PlanetModel {
-  
-  /** Planet model corresponding to sphere. */
-  public static final PlanetModel SPHERE = new PlanetModel(1.0,1.0);
-
-  /** Mean radius */
-  public static final double WGS84_MEAN = 6371009.0;
-  /** Polar radius */
-  public static final double WGS84_POLAR = 6356752.314245;
-  /** Equatorial radius */
-  public static final double WGS84_EQUATORIAL = 6378137.0;
-  /** Planet model corresponding to WGS84 */
-  public static final PlanetModel WGS84 = new PlanetModel(WGS84_EQUATORIAL/WGS84_MEAN,
-    WGS84_POLAR/WGS84_MEAN);
-
-  // Surface of the planet:
-  // x^2/a^2 + y^2/b^2 + z^2/c^2 = 1.0
-  // Scaling factors are a,b,c.  geo3d can only support models where a==b, so use ab instead.
-  
-  /** The x/y scaling factor */
-  public final double ab;
-  /** The z scaling factor */
-  public final double c;
-  /** The inverse of ab */
-  public final double inverseAb;
-  /** The inverse of c */
-  public final double inverseC;
-  /** The square of the inverse of ab */
-  public final double inverseAbSquared;
-  /** The square of the inverse of c */
-  public final double inverseCSquared;
-  /** The flattening value */
-  public final double flattening;
-  /** The square ratio */
-  public final double squareRatio;
-  
-  // We do NOT include radius, because all computations in geo3d are in radians, not meters.
-  
-  // Compute north and south pole for planet model, since these are commonly used.
-  
-  /** North pole */
-  public final GeoPoint NORTH_POLE;
-  /** South pole */
-  public final GeoPoint SOUTH_POLE;
-  /** Min X pole */
-  public final GeoPoint MIN_X_POLE;
-  /** Max X pole */
-  public final GeoPoint MAX_X_POLE;
-  /** Min Y pole */
-  public final GeoPoint MIN_Y_POLE;
-  /** Max Y pole */
-  public final GeoPoint MAX_Y_POLE;
-  
-  /** Constructor.
-   * @param ab is the x/y scaling factor.
-   * @param c is the z scaling factor.
-   */
-  public PlanetModel(final double ab, final double c) {
-    this.ab = ab;
-    this.c = c;
-    this.inverseAb = 1.0 / ab;
-    this.inverseC = 1.0 / c;
-    this.flattening = (ab - c) * inverseAb;
-    this.squareRatio = (ab * ab - c * c) / (c * c);
-    this.inverseAbSquared = inverseAb * inverseAb;
-    this.inverseCSquared = inverseC * inverseC;
-    this.NORTH_POLE = new GeoPoint(c, 0.0, 0.0, 1.0, Math.PI * 0.5, 0.0);
-    this.SOUTH_POLE = new GeoPoint(c, 0.0, 0.0, -1.0, -Math.PI * 0.5, 0.0);
-    this.MIN_X_POLE = new GeoPoint(ab, -1.0, 0.0, 0.0, 0.0, -Math.PI);
-    this.MAX_X_POLE = new GeoPoint(ab, 1.0, 0.0, 0.0, 0.0, 0.0);
-    this.MIN_Y_POLE = new GeoPoint(ab, 0.0, -1.0, 0.0, 0.0, -Math.PI * 0.5);
-    this.MAX_Y_POLE = new GeoPoint(ab, 0.0, 1.0, 0.0, 0.0, Math.PI * 0.5);
-  }
-  
-  /** Find the minimum magnitude of all points on the ellipsoid.
-   * @return the minimum magnitude for the planet.
-   */
-  public double getMinimumMagnitude() {
-    return Math.min(this.ab, this.c);
-  }
-
-  /** Find the maximum magnitude of all points on the ellipsoid.
-   * @return the maximum magnitude for the planet.
-   */
-  public double getMaximumMagnitude() {
-    return Math.max(this.ab, this.c);
-  }
-  
-  /** Find the minimum x value.
-   *@return the minimum X value.
-   */
-  public double getMinimumXValue() {
-    return -this.ab;
-  }
-  
-  /** Find the maximum x value.
-   *@return the maximum X value.
-   */
-  public double getMaximumXValue() {
-    return this.ab;
-  }
-
-  /** Find the minimum y value.
-   *@return the minimum Y value.
-   */
-  public double getMinimumYValue() {
-    return -this.ab;
-  }
-  
-  /** Find the maximum y value.
-   *@return the maximum Y value.
-   */
-  public double getMaximumYValue() {
-    return this.ab;
-  }
-  
-  /** Find the minimum z value.
-   *@return the minimum Z value.
-   */
-  public double getMinimumZValue() {
-    return -this.c;
-  }
-  
-  /** Find the maximum z value.
-   *@return the maximum Z value.
-   */
-  public double getMaximumZValue() {
-    return this.c;
-  }
-
-  /** Check if point is on surface.
-   * @param v is the point to check.
-   * @return true if the point is on the planet surface.
-   */
-  public boolean pointOnSurface(final Vector v) {
-    return pointOnSurface(v.x, v.y, v.z);
-  }
-  
-  /** Check if point is on surface.
-   * @param x is the x coord.
-   * @param y is the y coord.
-   * @param z is the z coord.
-   */
-  public boolean pointOnSurface(final double x, final double y, final double z) {
-    // Equation of planet surface is:
-    // x^2 / a^2 + y^2 / b^2 + z^2 / c^2 - 1 = 0
-    return Math.abs(x * x * inverseAb * inverseAb + y * y * inverseAb * inverseAb + z * z * inverseC * inverseC - 1.0) < Vector.MINIMUM_RESOLUTION;
-  }
-
-  /** Check if point is outside surface.
-   * @param v is the point to check.
-   * @return true if the point is outside the planet surface.
-   */
-  public boolean pointOutside(final Vector v) {
-    return pointOutside(v.x, v.y, v.z);
-  }
-  
-  /** Check if point is outside surface.
-   * @param x is the x coord.
-   * @param y is the y coord.
-   * @param z is the z coord.
-   */
-  public boolean pointOutside(final double x, final double y, final double z) {
-    // Equation of planet surface is:
-    // x^2 / a^2 + y^2 / b^2 + z^2 / c^2 - 1 = 0
-    return (x * x + y * y) * inverseAb * inverseAb + z * z * inverseC * inverseC - 1.0 > Vector.MINIMUM_RESOLUTION;
-  }
-  
-  /** Compute surface distance between two points.
-   * @param p1 is the first point.
-   * @param p2 is the second point.
-   * @return the adjusted angle, when multiplied by the mean earth radius, yields a surface distance.  This will differ
-   * from GeoPoint.arcDistance() only when the planet model is not a sphere. @see {@link org.apache.lucene.geo3d.GeoPoint#arcDistance(GeoPoint)}
-   */
-  public double surfaceDistance(final GeoPoint p1, final GeoPoint p2) {
-    final double latA = p1.getLatitude();
-    final double lonA = p1.getLongitude();
-    final double latB = p2.getLatitude();
-    final double lonB = p2.getLongitude();
-
-    final double L = lonB - lonA;
-    final double oF = 1.0 - this.flattening;
-    final double U1 = Math.atan(oF * Math.tan(latA));
-    final double U2 = Math.atan(oF * Math.tan(latB));
-    final double sU1 = Math.sin(U1);
-    final double cU1 = Math.cos(U1);
-    final double sU2 = Math.sin(U2);
-    final double cU2 = Math.cos(U2);
-
-    double sigma, sinSigma, cosSigma;
-    double cos2Alpha, cos2SigmaM;
-    
-    double lambda = L;
-    double iters = 100;
-
-    do {
-      final double sinLambda = Math.sin(lambda);
-      final double cosLambda = Math.cos(lambda);
-      sinSigma = Math.sqrt((cU2 * sinLambda) * (cU2 * sinLambda) + (cU1 * sU2 - sU1 * cU2 * cosLambda)
-          * (cU1 * sU2 - sU1 * cU2 * cosLambda));
-      if (Math.abs(sinSigma) < Vector.MINIMUM_RESOLUTION)
-        return 0.0;
-
-      cosSigma = sU1 * sU2 + cU1 * cU2 * cosLambda;
-      sigma = Math.atan2(sinSigma, cosSigma);
-      final double sinAlpha = cU1 * cU2 * sinLambda / sinSigma;
-      cos2Alpha = 1.0 - sinAlpha * sinAlpha;
-      cos2SigmaM = cosSigma - 2.0 * sU1 * sU2 / cos2Alpha;
-
-      final double c = this.flattening * 0.625 * cos2Alpha * (4.0 + this.flattening * (4.0 - 3.0 * cos2Alpha));
-      final double lambdaP = lambda;
-      lambda = L + (1.0 - c) * this.flattening * sinAlpha * (sigma + c * sinSigma * (cos2SigmaM + c * cosSigma *
-          (-1.0 + 2.0 * cos2SigmaM * cos2SigmaM)));
-      if (Math.abs(lambda - lambdaP) < Vector.MINIMUM_RESOLUTION)
-        break;
-    } while (--iters > 0);
-
-    if (iters == 0)
-      return 0.0;
-
-    final double uSq = cos2Alpha * this.squareRatio;
-    final double A = 1.0 + uSq * 0.00006103515625 * (4096.0 + uSq * (-768.0 + uSq * (320.0 - 175.0 * uSq)));
-    final double B = uSq * 0.0009765625 * (256.0 + uSq * (-128.0 + uSq * (74.0 - 47.0 * uSq)));
-    final double deltaSigma = B * sinSigma * (cos2SigmaM + B * 0.25 * (cosSigma * (-1.0 + 2.0 * cos2SigmaM * cos2SigmaM) - B * 0.16666666666666666666667 * cos2SigmaM
-            * (-3.0 + 4.0 * sinSigma * sinSigma) * (-3.0 + 4.0 * cos2SigmaM * cos2SigmaM)));
-
-    return this.c * A * (sigma - deltaSigma);
-  }
-
-  @Override
-  public boolean equals(final Object o) {
-    if (!(o instanceof PlanetModel))
-      return false;
-    final PlanetModel other = (PlanetModel)o;
-    return ab == other.ab && c == other.c;
-  }
-  
-  @Override
-  public int hashCode() {
-    return Double.hashCode(ab) + Double.hashCode(c);
-  }
-  
-  @Override
-  public String toString() {
-    if (this.equals(SPHERE)) {
-      return "PlanetModel.SPHERE";
-    } else if (this.equals(WGS84)) {
-      return "PlanetModel.WGS84";
-    } else {
-      return "PlanetModel(ab="+ab+" c="+c+")";
-    }
-  }
-}
-
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/PointInGeo3DShapeQuery.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/PointInGeo3DShapeQuery.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/PointInGeo3DShapeQuery.java
deleted file mode 100644
index 9e2132d..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/PointInGeo3DShapeQuery.java
+++ /dev/null
@@ -1,210 +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.geo3d;
-
-import java.io.IOException;
-
-import org.apache.lucene.index.PointValues.IntersectVisitor;
-import org.apache.lucene.index.PointValues;
-import org.apache.lucene.index.PointValues.Relation;
-import org.apache.lucene.index.LeafReader;
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.search.ConstantScoreScorer;
-import org.apache.lucene.search.ConstantScoreWeight;
-import org.apache.lucene.search.IndexSearcher;
-import org.apache.lucene.search.Query;
-import org.apache.lucene.search.Scorer;
-import org.apache.lucene.search.Weight;
-import org.apache.lucene.util.DocIdSetBuilder;
-import org.apache.lucene.util.NumericUtils;
-
-/** Finds all previously indexed points that fall within the specified polygon.
- *
- * <p>The field must be indexed using {@link Geo3DPoint}.
- *
- * @lucene.experimental */
-
-class PointInGeo3DShapeQuery extends Query {
-  final String field;
-  final GeoShape shape;
-
-  /** The lats/lons must be clockwise or counter-clockwise. */
-  public PointInGeo3DShapeQuery(String field, GeoShape shape) {
-    this.field = field;
-    this.shape = shape;
-
-    if (shape instanceof BasePlanetObject) {
-      BasePlanetObject planetObject = (BasePlanetObject) shape;
-      if (planetObject.getPlanetModel().equals(PlanetModel.WGS84) == false) {
-        throw new IllegalArgumentException("this qurey requires PlanetModel.WGS84, but got: " + planetObject.getPlanetModel());
-      }
-    }
-  }
-
-  @Override
-  public Weight createWeight(IndexSearcher searcher, boolean needsScores) throws IOException {
-
-    // I don't use RandomAccessWeight here: it's no good to approximate with "match all docs"; this is an inverted structure and should be
-    // used in the first pass:
-
-    return new ConstantScoreWeight(this) {
-
-      @Override
-      public Scorer scorer(LeafReaderContext context) throws IOException {
-        LeafReader reader = context.reader();
-        PointValues values = reader.getPointValues();
-        if (values == null) {
-          return null;
-        }
-
-        /*
-        XYZBounds bounds = new XYZBounds();
-        shape.getBounds(bounds);
-
-        final double planetMax = planetModel.getMaximumMagnitude();
-        if (planetMax != treeDV.planetMax) {
-          throw new IllegalStateException(planetModel + " is not the same one used during indexing: planetMax=" + planetMax + " vs indexing planetMax=" + treeDV.planetMax);
-        }
-        */
-
-        /*
-        GeoArea xyzSolid = GeoAreaFactory.makeGeoArea(planetModel,
-                                                      bounds.getMinimumX(),
-                                                      bounds.getMaximumX(),
-                                                      bounds.getMinimumY(),
-                                                      bounds.getMaximumY(),
-                                                      bounds.getMinimumZ(),
-                                                      bounds.getMaximumZ());
-
-        assert xyzSolid.getRelationship(shape) == GeoArea.WITHIN || xyzSolid.getRelationship(shape) == GeoArea.OVERLAPS: "expected WITHIN (1) or OVERLAPS (2) but got " + xyzSolid.getRelationship(shape) + "; shape="+shape+"; XYZSolid="+xyzSolid;
-        */
-
-        double planetMax = PlanetModel.WGS84.getMaximumMagnitude();
-
-        DocIdSetBuilder result = new DocIdSetBuilder(reader.maxDoc());
-
-        values.intersect(field,
-                         new IntersectVisitor() {
-
-                           @Override
-                           public void visit(int docID) {
-                             result.add(docID);
-                           }
-
-                           @Override
-                           public void visit(int docID, byte[] packedValue) {
-                             assert packedValue.length == 12;
-                             double x = Geo3DPoint.decodeDimension(packedValue, 0);
-                             double y = Geo3DPoint.decodeDimension(packedValue, Integer.BYTES);
-                             double z = Geo3DPoint.decodeDimension(packedValue, 2 * Integer.BYTES);
-                             if (shape.isWithin(x, y, z)) {
-                               result.add(docID);
-                             }
-                           }
-
-                           @Override
-                           public Relation compare(byte[] minPackedValue, byte[] maxPackedValue) {
-                             // Because the dimensional format operates in quantized (64 bit -> 32 bit) space, and the cell bounds
-                             // here are inclusive, we need to extend the bounds to the largest un-quantized values that
-                             // could quantize into these bounds.  The encoding (Geo3DUtil.encodeValue) does
-                             // a Math.round from double to long, so e.g. 1.4 -> 1, and -1.4 -> -1:
-                             double xMin = Geo3DUtil.decodeValueMin(planetMax, NumericUtils.sortableBytesToInt(minPackedValue, 0));
-                             double xMax = Geo3DUtil.decodeValueMax(planetMax, NumericUtils.sortableBytesToInt(maxPackedValue, 0));
-                             double yMin = Geo3DUtil.decodeValueMin(planetMax, NumericUtils.sortableBytesToInt(minPackedValue, 1 * Integer.BYTES));
-                             double yMax = Geo3DUtil.decodeValueMax(planetMax, NumericUtils.sortableBytesToInt(maxPackedValue, 1 * Integer.BYTES));
-                             double zMin = Geo3DUtil.decodeValueMin(planetMax, NumericUtils.sortableBytesToInt(minPackedValue, 2 * Integer.BYTES));
-                             double zMax = Geo3DUtil.decodeValueMax(planetMax, NumericUtils.sortableBytesToInt(maxPackedValue, 2 * Integer.BYTES));
-
-                             //System.out.println("  compare: x=" + cellXMin + "-" + cellXMax + " y=" + cellYMin + "-" + cellYMax + " z=" + cellZMin + "-" + cellZMax);
-                             assert xMin <= xMax;
-                             assert yMin <= yMax;
-                             assert zMin <= zMax;
-
-                             GeoArea xyzSolid = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84, xMin, xMax, yMin, yMax, zMin, zMax);
-
-                             switch(xyzSolid.getRelationship(shape)) {
-                             case GeoArea.CONTAINS:
-                               // Shape fully contains the cell
-                               //System.out.println("    inside");
-                               return Relation.CELL_INSIDE_QUERY;
-                             case GeoArea.OVERLAPS:
-                               // They do overlap but neither contains the other:
-                               //System.out.println("    crosses1");
-                               return Relation.CELL_CROSSES_QUERY;
-                             case GeoArea.WITHIN:
-                               // Cell fully contains the shape:
-                               //System.out.println("    crosses2");
-                               // return Relation.SHAPE_INSIDE_CELL;
-                               return Relation.CELL_CROSSES_QUERY;
-                             case GeoArea.DISJOINT:
-                               // They do not overlap at all
-                               //System.out.println("    outside");
-                               return Relation.CELL_OUTSIDE_QUERY;
-                             default:
-                               assert false;
-                               return Relation.CELL_CROSSES_QUERY;
-                             }
-                           }
-                         });
-
-        return new ConstantScoreScorer(this, score(), result.build().iterator());
-      }
-    };
-  }
-
-  public String getField() {
-    return field;
-  }
-
-  public GeoShape getShape() {
-    return shape;
-  }
-
-  @Override
-  @SuppressWarnings({"unchecked","rawtypes"})
-  public boolean equals(Object o) {
-    if (this == o) return true;
-    if (o == null || getClass() != o.getClass()) return false;
-    if (!super.equals(o)) return false;
-
-    PointInGeo3DShapeQuery that = (PointInGeo3DShapeQuery) o;
-
-    return shape.equals(that.shape);
-  }
-
-  @Override
-  public final int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + shape.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString(String field) {
-    final StringBuilder sb = new StringBuilder();
-    sb.append(getClass().getSimpleName());
-    sb.append(':');
-    if (this.field.equals(field) == false) {
-      sb.append(" field=");
-      sb.append(this.field);
-      sb.append(':');
-    }
-    sb.append(" Shape: ");
-    sb.append(shape);
-    return sb.toString();
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/SidedPlane.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/SidedPlane.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/SidedPlane.java
deleted file mode 100755
index 7fc543d..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/SidedPlane.java
+++ /dev/null
@@ -1,175 +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.geo3d;
-
-/**
- * Combination of a plane, and a sign value indicating what evaluation values are on the correct
- * side of the plane.
- *
- * @lucene.experimental
- */
-public class SidedPlane extends Plane implements Membership {
-  /** The sign value for evaluation of a point on the correct side of the plane */
-  public final double sigNum;
-
-  /**
-   * Construct a SidedPlane identical to an existing one, but reversed.
-   *
-   * @param sidedPlane is the existing plane.
-   */
-  public SidedPlane(SidedPlane sidedPlane) {
-    super(sidedPlane, sidedPlane.D);
-    this.sigNum = -sidedPlane.sigNum;
-  }
-
-  /**
-   * Construct a sided plane from a pair of vectors describing points, and including
-   * origin, plus a point p which describes the side.
-   *
-   * @param p point to evaluate
-   * @param A is the first in-plane point
-   * @param B is the second in-plane point
-   */
-  public SidedPlane(Vector p, Vector A, Vector B) {
-    super(A, B);
-    sigNum = Math.signum(evaluate(p));
-    if (sigNum == 0.0)
-      throw new IllegalArgumentException("Cannot determine sidedness because check point is on plane.");
-  }
-
-  /**
-   * Construct a sided plane from a point and a Z coordinate.
-   *
-   * @param p      point to evaluate.
-   * @param planetModel is the planet model.
-   * @param sinLat is the sin of the latitude of the plane.
-   */
-  public SidedPlane(Vector p, final PlanetModel planetModel, double sinLat) {
-    super(planetModel, sinLat);
-    sigNum = Math.signum(evaluate(p));
-    if (sigNum == 0.0)
-      throw new IllegalArgumentException("Cannot determine sidedness because check point is on plane.");
-  }
-
-  /**
-   * Construct a sided vertical plane from a point and specified x and y coordinates.
-   *
-   * @param p point to evaluate.
-   * @param x is the specified x.
-   * @param y is the specified y.
-   */
-  public SidedPlane(Vector p, double x, double y) {
-    super(x, y);
-    sigNum = Math.signum(evaluate(p));
-    if (sigNum == 0.0)
-      throw new IllegalArgumentException("Cannot determine sidedness because check point is on plane.");
-  }
-
-  /**
-   * Construct a sided plane with a normal vector and offset.
-   *
-   * @param p point to evaluate.
-   * @param v is the normal vector.
-   * @param D is the origin offset for the plan.
-   */
-  public SidedPlane(Vector p, Vector v, double D) {
-    super(v, D);
-    sigNum = Math.signum(evaluate(p));
-    if (sigNum == 0.0)
-      throw new IllegalArgumentException("Cannot determine sidedness because check point is on plane.");
-  }
-
-  /**
-   * Construct a sided plane with a normal vector and offset.
-   *
-   * @param pX X coord of point to evaluate.
-   * @param pY Y coord of point to evaluate.
-   * @param pZ Z coord of point to evaluate.
-   * @param v is the normal vector.
-   * @param D is the origin offset for the plan.
-   */
-  public SidedPlane(double pX, double pY, double pZ, Vector v, double D) {
-    super(v, D);
-    sigNum = Math.signum(evaluate(pX,pY,pZ));
-    if (sigNum == 0.0)
-      throw new IllegalArgumentException("Cannot determine sidedness because check point is on plane.");
-  }
-
-  /** Construct a sided plane from two points and a third normal vector.
-   */
-  public static SidedPlane constructNormalizedPerpendicularSidedPlane(final Vector insidePoint,
-    final Vector normalVector, final Vector point1, final Vector point2) {
-    final Vector pointsVector = new Vector(point1.x - point2.x, point1.y - point2.y, point1.z - point2.z);
-    final Vector newNormalVector = new Vector(normalVector, pointsVector);
-    try {
-      // To construct the plane, we now just need D, which is simply the negative of the evaluation of the circle normal vector at one of the points.
-      return new SidedPlane(insidePoint, newNormalVector, -newNormalVector.dotProduct(point1));
-    } catch (IllegalArgumentException e) {
-      return null;
-    }
-  }
-  
-  /** Construct a sided plane from three points.
-   */
-  public static SidedPlane constructNormalizedThreePointSidedPlane(final Vector insidePoint,
-    final Vector point1, final Vector point2, final Vector point3) {
-    try {
-      final Vector planeNormal = new Vector(
-        new Vector(point1.x - point2.x, point1.y - point2.y, point1.z - point2.z),
-        new Vector(point2.x - point3.x, point2.y - point3.y, point2.z - point3.z));
-      return new SidedPlane(insidePoint, planeNormal, -planeNormal.dotProduct(point2));
-    } catch (IllegalArgumentException e) {
-      return null;
-    }
-  }
-
-  @Override
-  public boolean isWithin(double x, double y, double z) {
-    double evalResult = evaluate(x, y, z);
-    if (Math.abs(evalResult) < MINIMUM_RESOLUTION)
-      return true;
-    double sigNum = Math.signum(evalResult);
-    return sigNum == this.sigNum;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) return true;
-    if (!(o instanceof SidedPlane)) return false;
-    if (!super.equals(o)) return false;
-
-    SidedPlane that = (SidedPlane) o;
-
-    return Double.compare(that.sigNum, sigNum) == 0;
-
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    long temp;
-    temp = Double.doubleToLongBits(sigNum);
-    result = 31 * result + (int) (temp ^ (temp >>> 32));
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "[A=" + x + ", B=" + y + ", C=" + z + ", D=" + D + ", side=" + sigNum + "]";
-  }
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/StandardXYZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/StandardXYZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/StandardXYZSolid.java
deleted file mode 100644
index cd54225..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/StandardXYZSolid.java
+++ /dev/null
@@ -1,417 +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.geo3d;
-
-/**
- * 3D rectangle, bounded on six sides by X,Y,Z limits
- *
- * @lucene.internal
- */
-public class StandardXYZSolid extends BaseXYZSolid {
-
-  /** Whole world? */
-  protected final boolean isWholeWorld;
-  /** Min-X plane */
-  protected final SidedPlane minXPlane;
-  /** Max-X plane */
-  protected final SidedPlane maxXPlane;
-  /** Min-Y plane */
-  protected final SidedPlane minYPlane;
-  /** Max-Y plane */
-  protected final SidedPlane maxYPlane;
-  /** Min-Z plane */
-  protected final SidedPlane minZPlane;
-  /** Max-Z plane */
-  protected final SidedPlane maxZPlane;
-  
-  /** These are the edge points of the shape, which are defined to be at least one point on
-   * each surface area boundary.  In the case of a solid, this includes points which represent
-   * the intersection of XYZ bounding planes and the planet, as well as points representing
-   * the intersection of single bounding planes with the planet itself.
-   */
-  protected final GeoPoint[] edgePoints;
-
-  /** Notable points for minXPlane */
-  protected final GeoPoint[] notableMinXPoints;
-  /** Notable points for maxXPlane */
-  protected final GeoPoint[] notableMaxXPoints;
-  /** Notable points for minYPlane */
-  protected final GeoPoint[] notableMinYPoints;
-  /** Notable points for maxYPlane */
-  protected final GeoPoint[] notableMaxYPoints;
-  /** Notable points for minZPlane */
-  protected final GeoPoint[] notableMinZPoints;
-  /** Notable points for maxZPlane */
-  protected final GeoPoint[] notableMaxZPoints;
-
-  /**
-   * Sole constructor
-   *
-   *@param planetModel is the planet model.
-   *@param minX is the minimum X value.
-   *@param maxX is the maximum X value.
-   *@param minY is the minimum Y value.
-   *@param maxY is the maximum Y value.
-   *@param minZ is the minimum Z value.
-   *@param maxZ is the maximum Z value.
-   */
-  public StandardXYZSolid(final PlanetModel planetModel,
-    final double minX,
-    final double maxX,
-    final double minY,
-    final double maxY,
-    final double minZ,
-    final double maxZ) {
-    super(planetModel);
-    // Argument checking
-    if (maxX - minX < Vector.MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("X values in wrong order or identical");
-    if (maxY - minY < Vector.MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("Y values in wrong order or identical");
-    if (maxZ - minZ < Vector.MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("Z values in wrong order or identical");
-
-    final double worldMinX = planetModel.getMinimumXValue();
-    final double worldMaxX = planetModel.getMaximumXValue();
-    final double worldMinY = planetModel.getMinimumYValue();
-    final double worldMaxY = planetModel.getMaximumYValue();
-    final double worldMinZ = planetModel.getMinimumZValue();
-    final double worldMaxZ = planetModel.getMaximumZValue();
-    
-    // We must distinguish between the case where the solid represents the entire world,
-    // and when the solid has no overlap with any part of the surface.  In both cases,
-    // there will be no edgepoints.
-    isWholeWorld =
-        (minX - worldMinX < -Vector.MINIMUM_RESOLUTION) &&
-        (maxX - worldMaxX > Vector.MINIMUM_RESOLUTION) &&
-        (minY - worldMinY < -Vector.MINIMUM_RESOLUTION) &&
-        (maxY - worldMaxY > Vector.MINIMUM_RESOLUTION) &&
-        (minZ - worldMinZ < -Vector.MINIMUM_RESOLUTION) &&
-        (maxZ - worldMaxZ > Vector.MINIMUM_RESOLUTION);
-
-    if (isWholeWorld) {
-      minXPlane = null;
-      maxXPlane = null;
-      minYPlane = null;
-      maxYPlane = null;
-      minZPlane = null;
-      maxZPlane = null;
-      notableMinXPoints = null;
-      notableMaxXPoints = null;
-      notableMinYPoints = null;
-      notableMaxYPoints = null;
-      notableMinZPoints = null;
-      notableMaxZPoints = null;
-      edgePoints = null;
-    } else {
-      // Construct the planes
-      minXPlane = new SidedPlane(maxX,0.0,0.0,xUnitVector,-minX);
-      maxXPlane = new SidedPlane(minX,0.0,0.0,xUnitVector,-maxX);
-      minYPlane = new SidedPlane(0.0,maxY,0.0,yUnitVector,-minY);
-      maxYPlane = new SidedPlane(0.0,minY,0.0,yUnitVector,-maxY);
-      minZPlane = new SidedPlane(0.0,0.0,maxZ,zUnitVector,-minZ);
-      maxZPlane = new SidedPlane(0.0,0.0,minZ,zUnitVector,-maxZ);
-      
-      // We need at least one point on the planet surface for each manifestation of the shape.
-      // There can be up to 2 (on opposite sides of the world).  But we have to go through
-      // 12 combinations of adjacent planes in order to find out if any have 2 intersection solution.
-      // Typically, this requires 12 square root operations. 
-      final GeoPoint[] minXminY = minXPlane.findIntersections(planetModel,minYPlane,maxXPlane,maxYPlane,minZPlane,maxZPlane);
-      final GeoPoint[] minXmaxY = minXPlane.findIntersections(planetModel,maxYPlane,maxXPlane,minYPlane,minZPlane,maxZPlane);
-      final GeoPoint[] minXminZ = minXPlane.findIntersections(planetModel,minZPlane,maxXPlane,maxZPlane,minYPlane,maxYPlane);
-      final GeoPoint[] minXmaxZ = minXPlane.findIntersections(planetModel,maxZPlane,maxXPlane,minZPlane,minYPlane,maxYPlane);
-
-      final GeoPoint[] maxXminY = maxXPlane.findIntersections(planetModel,minYPlane,minXPlane,maxYPlane,minZPlane,maxZPlane);
-      final GeoPoint[] maxXmaxY = maxXPlane.findIntersections(planetModel,maxYPlane,minXPlane,minYPlane,minZPlane,maxZPlane);
-      final GeoPoint[] maxXminZ = maxXPlane.findIntersections(planetModel,minZPlane,minXPlane,maxZPlane,minYPlane,maxYPlane);
-      final GeoPoint[] maxXmaxZ = maxXPlane.findIntersections(planetModel,maxZPlane,minXPlane,minZPlane,minYPlane,maxYPlane);
-      
-      final GeoPoint[] minYminZ = minYPlane.findIntersections(planetModel,minZPlane,maxYPlane,maxZPlane,minXPlane,maxXPlane);
-      final GeoPoint[] minYmaxZ = minYPlane.findIntersections(planetModel,maxZPlane,maxYPlane,minZPlane,minXPlane,maxXPlane);
-      final GeoPoint[] maxYminZ = maxYPlane.findIntersections(planetModel,minZPlane,minYPlane,maxZPlane,minXPlane,maxXPlane);
-      final GeoPoint[] maxYmaxZ = maxYPlane.findIntersections(planetModel,maxZPlane,minYPlane,minZPlane,minXPlane,maxXPlane);
-      
-      notableMinXPoints = glueTogether(minXminY, minXmaxY, minXminZ, minXmaxZ);
-      notableMaxXPoints = glueTogether(maxXminY, maxXmaxY, maxXminZ, maxXmaxZ);
-      notableMinYPoints = glueTogether(minXminY, maxXminY, minYminZ, minYmaxZ);
-      notableMaxYPoints = glueTogether(minXmaxY, maxXmaxY, maxYminZ, maxYmaxZ);
-      notableMinZPoints = glueTogether(minXminZ, maxXminZ, minYminZ, maxYminZ);
-      notableMaxZPoints = glueTogether(minXmaxZ, maxXmaxZ, minYmaxZ, maxYmaxZ);
-
-      // Now, compute the edge points.
-      // This is the trickiest part of setting up an XYZSolid.  We've computed intersections already, so
-      // we'll start there.
-      // There can be a number of shapes, each of which needs an edgepoint.  Each side by itself might contribute
-      // an edgepoint, for instance, if the plane describing that side intercepts the planet in such a way that the ellipse
-      // of interception does not meet any other planes.  Plane intersections can each contribute 0, 1, or 2 edgepoints.
-      //
-      // All of this makes for a lot of potential edgepoints, but I believe these can be pruned back with careful analysis.
-      // I haven't yet done that analysis, however, so I will treat them all as individual edgepoints.
-      
-      // The cases we are looking for are when the four corner points for any given
-      // plane are all outside of the world, AND that plane intersects the world.
-      // There are eight corner points all told; we must evaluate these WRT the planet surface.
-      final boolean minXminYminZ = planetModel.pointOutside(minX, minY, minZ);
-      final boolean minXminYmaxZ = planetModel.pointOutside(minX, minY, maxZ);
-      final boolean minXmaxYminZ = planetModel.pointOutside(minX, maxY, minZ);
-      final boolean minXmaxYmaxZ = planetModel.pointOutside(minX, maxY, maxZ);
-      final boolean maxXminYminZ = planetModel.pointOutside(maxX, minY, minZ);
-      final boolean maxXminYmaxZ = planetModel.pointOutside(maxX, minY, maxZ);
-      final boolean maxXmaxYminZ = planetModel.pointOutside(maxX, maxY, minZ);
-      final boolean maxXmaxYmaxZ = planetModel.pointOutside(maxX, maxY, maxZ);
-        
-      // Look at single-plane/world intersections.
-      // We detect these by looking at the world model and noting its x, y, and z bounds.
-
-      final GeoPoint[] minXEdges;
-      if (minX - worldMinX >= -Vector.MINIMUM_RESOLUTION && minX - worldMaxX <= Vector.MINIMUM_RESOLUTION &&
-        minY < 0.0 && maxY > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
-        minXminYminZ && minXminYmaxZ && minXmaxYminZ && minXmaxYmaxZ) {
-        // Find any point on the minX plane that intersects the world
-        // First construct a perpendicular plane that will allow us to find a sample point.
-        // This plane is vertical and goes through the points (0,0,0) and (1,0,0)
-        // Then use it to compute a sample point.
-        final GeoPoint intPoint = minXPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
-        if (intPoint != null) {
-          minXEdges = new GeoPoint[]{intPoint};
-        } else {
-          // No intersection found?
-          minXEdges = EMPTY_POINTS;
-        }
-      } else {
-        minXEdges = EMPTY_POINTS;
-      }
-      
-      final GeoPoint[] maxXEdges;
-      if (maxX - worldMinX >= -Vector.MINIMUM_RESOLUTION && maxX - worldMaxX <= Vector.MINIMUM_RESOLUTION &&
-        minY < 0.0 && maxY > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
-        maxXminYminZ && maxXminYmaxZ && maxXmaxYminZ && maxXmaxYmaxZ) {
-        // Find any point on the maxX plane that intersects the world
-        // First construct a perpendicular plane that will allow us to find a sample point.
-        // This plane is vertical and goes through the points (0,0,0) and (1,0,0)
-        // Then use it to compute a sample point.
-        final GeoPoint intPoint = maxXPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
-        if (intPoint != null) {
-          maxXEdges = new GeoPoint[]{intPoint};
-        } else {
-          maxXEdges = EMPTY_POINTS;
-        }
-      } else {
-        maxXEdges = EMPTY_POINTS;
-      }
-      
-      final GeoPoint[] minYEdges;
-      if (minY - worldMinY >= -Vector.MINIMUM_RESOLUTION && minY - worldMaxY <= Vector.MINIMUM_RESOLUTION &&
-        minX < 0.0 && maxX > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
-        minXminYminZ && minXminYmaxZ && maxXminYminZ && maxXminYmaxZ) {
-        // Find any point on the minY plane that intersects the world
-        // First construct a perpendicular plane that will allow us to find a sample point.
-        // This plane is vertical and goes through the points (0,0,0) and (0,1,0)
-        // Then use it to compute a sample point.
-        final GeoPoint intPoint = minYPlane.getSampleIntersectionPoint(planetModel, yVerticalPlane);
-        if (intPoint != null) {
-          minYEdges = new GeoPoint[]{intPoint};
-        } else {
-          minYEdges = EMPTY_POINTS;
-        }
-      } else {
-        minYEdges = EMPTY_POINTS;
-      }
-      
-      final GeoPoint[] maxYEdges;
-      if (maxY - worldMinY >= -Vector.MINIMUM_RESOLUTION && maxY - worldMaxY <= Vector.MINIMUM_RESOLUTION &&
-        minX < 0.0 && maxX > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
-        minXmaxYminZ && minXmaxYmaxZ && maxXmaxYminZ && maxXmaxYmaxZ) {
-        // Find any point on the maxY plane that intersects the world
-        // First construct a perpendicular plane that will allow us to find a sample point.
-        // This plane is vertical and goes through the points (0,0,0) and (0,1,0)
-        // Then use it to compute a sample point.
-        final GeoPoint intPoint = maxYPlane.getSampleIntersectionPoint(planetModel, yVerticalPlane);
-        if (intPoint != null) {
-          maxYEdges = new GeoPoint[]{intPoint};
-        } else {
-          maxYEdges = EMPTY_POINTS;
-        }
-      } else {
-        maxYEdges = EMPTY_POINTS;
-      }
-      
-      final GeoPoint[] minZEdges;
-      if (minZ - worldMinZ >= -Vector.MINIMUM_RESOLUTION && minZ - worldMaxZ <= Vector.MINIMUM_RESOLUTION &&
-        minX < 0.0 && maxX > 0.0 && minY < 0.0 && maxY > 0.0 &&
-        minXminYminZ && minXmaxYminZ && maxXminYminZ && maxXmaxYminZ) {
-        // Find any point on the minZ plane that intersects the world
-        // First construct a perpendicular plane that will allow us to find a sample point.
-        // This plane is vertical and goes through the points (0,0,0) and (1,0,0)
-        // Then use it to compute a sample point.
-        final GeoPoint intPoint = minZPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
-        if (intPoint != null) {
-          minZEdges = new GeoPoint[]{intPoint};
-        } else {
-          minZEdges = EMPTY_POINTS;
-        }
-      } else {
-        minZEdges = EMPTY_POINTS;
-      }
-      
-      final GeoPoint[] maxZEdges;
-      if (maxZ - worldMinZ >= -Vector.MINIMUM_RESOLUTION && maxZ - worldMaxZ <= Vector.MINIMUM_RESOLUTION &&
-        minX < 0.0 && maxX > 0.0 && minY < 0.0 && maxY > 0.0 &&
-        minXminYmaxZ && minXmaxYmaxZ && maxXminYmaxZ && maxXmaxYmaxZ) {
-        // Find any point on the maxZ plane that intersects the world
-        // First construct a perpendicular plane that will allow us to find a sample point.
-        // This plane is vertical and goes through the points (0,0,0) and (1,0,0) (that is, its orientation doesn't matter)
-        // Then use it to compute a sample point.
-        final GeoPoint intPoint = maxZPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
-        if (intPoint != null) {
-          maxZEdges = new GeoPoint[]{intPoint};
-        } else {
-          maxZEdges = EMPTY_POINTS;
-        }
-      } else {
-        maxZEdges = EMPTY_POINTS;
-      }
-      
-      // Glue everything together.  This is not a minimal set of edgepoints, as of now, but it does completely describe all shapes on the
-      // planet.
-      this.edgePoints = glueTogether(minXminY, minXmaxY, minXminZ, minXmaxZ,
-        maxXminY, maxXmaxY, maxXminZ, maxXmaxZ,
-        minYminZ, minYmaxZ, maxYminZ, maxYmaxZ,
-        minXEdges, maxXEdges, minYEdges, maxYEdges, minZEdges, maxZEdges);
-    }
-  }
-
-  @Override
-  protected GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-  
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    if (isWholeWorld) {
-      return true;
-    }
-    return minXPlane.isWithin(x, y, z) &&
-      maxXPlane.isWithin(x, y, z) &&
-      minYPlane.isWithin(x, y, z) &&
-      maxYPlane.isWithin(x, y, z) &&
-      minZPlane.isWithin(x, y, z) &&
-      maxZPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    if (isWholeWorld) {
-      if (path.getEdgePoints().length > 0)
-        return WITHIN;
-      return OVERLAPS;
-    }
-    
-    /*
-    for (GeoPoint p : getEdgePoints()) {
-      System.err.println(" Edge point "+p+" path.isWithin()? "+path.isWithin(p));
-    }
-    
-    for (GeoPoint p : path.getEdgePoints()) {
-      System.err.println(" path edge point "+p+" isWithin()? "+isWithin(p)+" minx="+minXPlane.evaluate(p)+" maxx="+maxXPlane.evaluate(p)+" miny="+minYPlane.evaluate(p)+" maxy="+maxYPlane.evaluate(p)+" minz="+minZPlane.evaluate(p)+" maxz="+maxZPlane.evaluate(p));
-    }
-    */
-    
-    //System.err.println(this+" getrelationship with "+path);
-    final int insideRectangle = isShapeInsideArea(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some shape points inside area");
-      return OVERLAPS;
-    }
-
-    // Figure out if the entire XYZArea is contained by the shape.
-    final int insideShape = isAreaInsideShape(path);
-    if (insideShape == SOME_INSIDE) {
-      //System.err.println(" some area points inside shape");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
-      //System.err.println(" inside of each other");
-      return OVERLAPS;
-    }
-
-    if (path.intersects(minXPlane, notableMinXPoints, maxXPlane, minYPlane, maxYPlane, minZPlane, maxZPlane) ||
-        path.intersects(maxXPlane, notableMaxXPoints, minXPlane, minYPlane, maxYPlane, minZPlane, maxZPlane) ||
-        path.intersects(minYPlane, notableMinYPoints, maxYPlane, minXPlane, maxXPlane, minZPlane, maxZPlane) ||
-        path.intersects(maxYPlane, notableMaxYPoints, minYPlane, minXPlane, maxXPlane, minZPlane, maxZPlane) ||
-        path.intersects(minZPlane, notableMinZPoints, maxZPlane, minXPlane, maxXPlane, minYPlane, maxYPlane) ||
-        path.intersects(maxZPlane, notableMaxZPoints, minZPlane, minXPlane, maxXPlane, minYPlane, maxYPlane)) {
-      //System.err.println(" edges intersect");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      //System.err.println(" all shape points inside area");
-      return WITHIN;
-    }
-
-    if (insideShape == ALL_INSIDE) {
-      //System.err.println(" all area points inside shape");
-      return CONTAINS;
-    }
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof StandardXYZSolid))
-      return false;
-    StandardXYZSolid other = (StandardXYZSolid) o;
-    if (!super.equals(other) ||
-      other.isWholeWorld != isWholeWorld) {
-      return false;
-    }
-    if (!isWholeWorld) {
-      return other.minXPlane.equals(minXPlane) &&
-        other.maxXPlane.equals(maxXPlane) &&
-        other.minYPlane.equals(minYPlane) &&
-        other.maxYPlane.equals(maxYPlane) &&
-        other.minZPlane.equals(minZPlane) &&
-        other.maxZPlane.equals(maxZPlane);
-    }
-    return true;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + (isWholeWorld?1:0);
-    if (!isWholeWorld) {
-      result = 31 * result  + minXPlane.hashCode();
-      result = 31 * result  + maxXPlane.hashCode();
-      result = 31 * result  + minYPlane.hashCode();
-      result = 31 * result  + maxYPlane.hashCode();
-      result = 31 * result  + minZPlane.hashCode();
-      result = 31 * result  + maxZPlane.hashCode();
-    }
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "StandardXYZSolid: {planetmodel="+planetModel+", isWholeWorld="+isWholeWorld+", minXplane="+minXPlane+", maxXplane="+maxXPlane+", minYplane="+minYPlane+", maxYplane="+maxYPlane+", minZplane="+minZPlane+", maxZplane="+maxZPlane+"}";
-  }
-  
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Tools.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Tools.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Tools.java
deleted file mode 100755
index 89d37aa..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Tools.java
+++ /dev/null
@@ -1,41 +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.geo3d;
-
-/**
- * Static methods globally useful for 3d geometric work.
- *
- * @lucene.experimental
- */
-public class Tools {
-  private Tools() {
-  }
-
-  /**
-   * Java acos yields a NAN if you take an arc-cos of an
-   * angle that's just a tiny bit greater than 1.0, so
-   * here's a more resilient version.
-   */
-  public static double safeAcos(double value) {
-    if (value > 1.0)
-      value = 1.0;
-    else if (value < -1.0)
-      value = -1.0;
-    return Math.acos(value);
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Vector.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Vector.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Vector.java
deleted file mode 100755
index 1a3972d..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Vector.java
+++ /dev/null
@@ -1,378 +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.geo3d;
-
-/**
- * A 3d vector in space, not necessarily
- * going through the origin.
- *
- * @lucene.experimental
- */
-public class Vector {
-  /**
-   * Values that are all considered to be essentially zero have a magnitude
-   * less than this.
-   */
-  public static final double MINIMUM_RESOLUTION = 1.0e-12;
-  /**
-   * For squared quantities, the bound is squared too.
-   */
-  public static final double MINIMUM_RESOLUTION_SQUARED = MINIMUM_RESOLUTION * MINIMUM_RESOLUTION;
-  /**
-   * For cubed quantities, cube the bound.
-   */
-  public static final double MINIMUM_RESOLUTION_CUBED = MINIMUM_RESOLUTION_SQUARED * MINIMUM_RESOLUTION;
-
-  /** The x value */
-  public final double x;
-  /** The y value */
-  public final double y;
-  /** The z value */
-  public final double z;
-
-  /**
-   * Construct from (U.S.) x,y,z coordinates.
-   *@param x is the x value.
-   *@param y is the y value.
-   *@param z is the z value.
-   */
-  public Vector(double x, double y, double z) {
-    this.x = x;
-    this.y = y;
-    this.z = z;
-  }
-
-  /**
-   * Construct a vector that is perpendicular to
-   * two other (non-zero) vectors.  If the vectors are parallel,
-   * IllegalArgumentException will be thrown.
-   * Produces a normalized final vector.
-   *
-   * @param A is the first vector
-   * @param B is the second
-   */
-  public Vector(final Vector A, final Vector B) {
-    // x = u2v3 - u3v2
-    // y = u3v1 - u1v3
-    // z = u1v2 - u2v1
-    final double thisX = A.y * B.z - A.z * B.y;
-    final double thisY = A.z * B.x - A.x * B.z;
-    final double thisZ = A.x * B.y - A.y * B.x;
-    final double magnitude = magnitude(thisX, thisY, thisZ);
-    if (Math.abs(magnitude) < MINIMUM_RESOLUTION) {
-      throw new IllegalArgumentException("Degenerate/parallel vector constructed");
-    }
-    final double inverseMagnitude = 1.0 / magnitude;
-    this.x = thisX * inverseMagnitude;
-    this.y = thisY * inverseMagnitude;
-    this.z = thisZ * inverseMagnitude;
-  }
-
-  /** Compute a magnitude of an x,y,z value.
-   */
-  public static double magnitude(final double x, final double y, final double z) {
-    return Math.sqrt(x*x + y*y + z*z);
-  }
-  
-  /**
-   * Compute a normalized unit vector based on the current vector.
-   *
-   * @return the normalized vector, or null if the current vector has
-   * a magnitude of zero.
-   */
-  public Vector normalize() {
-    double denom = magnitude();
-    if (denom < MINIMUM_RESOLUTION)
-      // Degenerate, can't normalize
-      return null;
-    double normFactor = 1.0 / denom;
-    return new Vector(x * normFactor, y * normFactor, z * normFactor);
-  }
-
-  /**
-   * Do a dot product.
-   *
-   * @param v is the vector to multiply.
-   * @return the result.
-   */
-  public double dotProduct(final Vector v) {
-    return this.x * v.x + this.y * v.y + this.z * v.z;
-  }
-
-  /**
-   * Do a dot product.
-   *
-   * @param x is the x value of the vector to multiply.
-   * @param y is the y value of the vector to multiply.
-   * @param z is the z value of the vector to multiply.
-   * @return the result.
-   */
-  public double dotProduct(final double x, final double y, final double z) {
-    return this.x * x + this.y * y + this.z * z;
-  }
-
-  /**
-   * Determine if this vector, taken from the origin,
-   * describes a point within a set of planes.
-   *
-   * @param bounds     is the first part of the set of planes.
-   * @param moreBounds is the second part of the set of planes.
-   * @return true if the point is within the bounds.
-   */
-  public boolean isWithin(final Membership[] bounds, final Membership[] moreBounds) {
-    // Return true if the point described is within all provided bounds
-    //System.err.println("  checking if "+this+" is within bounds");
-    for (Membership bound : bounds) {
-      if (bound != null && !bound.isWithin(this)) {
-        //System.err.println("    NOT within "+bound);
-        return false;
-      }
-    }
-    for (Membership bound : moreBounds) {
-      if (bound != null && !bound.isWithin(this)) {
-        //System.err.println("    NOT within "+bound);
-        return false;
-      }
-    }
-    //System.err.println("    is within");
-    return true;
-  }
-
-  /**
-   * Translate vector.
-   */
-  public Vector translate(final double xOffset, final double yOffset, final double zOffset) {
-    return new Vector(x - xOffset, y - yOffset, z - zOffset);
-  }
-
-  /**
-   * Rotate vector counter-clockwise in x-y by an angle.
-   */
-  public Vector rotateXY(final double angle) {
-    return rotateXY(Math.sin(angle), Math.cos(angle));
-  }
-
-  /**
-   * Rotate vector counter-clockwise in x-y by an angle, expressed as sin and cos.
-   */
-  public Vector rotateXY(final double sinAngle, final double cosAngle) {
-    return new Vector(x * cosAngle - y * sinAngle, x * sinAngle + y * cosAngle, z);
-  }
-
-  /**
-   * Rotate vector counter-clockwise in x-z by an angle.
-   */
-  public Vector rotateXZ(final double angle) {
-    return rotateXZ(Math.sin(angle), Math.cos(angle));
-  }
-
-  /**
-   * Rotate vector counter-clockwise in x-z by an angle, expressed as sin and cos.
-   */
-  public Vector rotateXZ(final double sinAngle, final double cosAngle) {
-    return new Vector(x * cosAngle - z * sinAngle, y, x * sinAngle + z * cosAngle);
-  }
-
-  /**
-   * Rotate vector counter-clockwise in z-y by an angle.
-   */
-  public Vector rotateZY(final double angle) {
-    return rotateZY(Math.sin(angle), Math.cos(angle));
-  }
-
-  /**
-   * Rotate vector counter-clockwise in z-y by an angle, expressed as sin and cos.
-   */
-  public Vector rotateZY(final double sinAngle, final double cosAngle) {
-    return new Vector(x, z * sinAngle + y * cosAngle, z * cosAngle - y * sinAngle);
-  }
-
-  /**
-   * Compute the square of a straight-line distance to a point described by the
-   * vector taken from the origin.
-   * Monotonically increasing for arc distances up to PI.
-   *
-   * @param v is the vector to compute a distance to.
-   * @return the square of the linear distance.
-   */
-  public double linearDistanceSquared(final Vector v) {
-    double deltaX = this.x - v.x;
-    double deltaY = this.y - v.y;
-    double deltaZ = this.z - v.z;
-    return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
-  }
-
-  /**
-   * Compute the square of a straight-line distance to a point described by the
-   * vector taken from the origin.
-   * Monotonically increasing for arc distances up to PI.
-   *
-   * @param x is the x part of the vector to compute a distance to.
-   * @param y is the y part of the vector to compute a distance to.
-   * @param z is the z part of the vector to compute a distance to.
-   * @return the square of the linear distance.
-   */
-  public double linearDistanceSquared(final double x, final double y, final double z) {
-    double deltaX = this.x - x;
-    double deltaY = this.y - y;
-    double deltaZ = this.z - z;
-    return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
-  }
-
-  /**
-   * Compute the straight-line distance to a point described by the
-   * vector taken from the origin.
-   * Monotonically increasing for arc distances up to PI.
-   *
-   * @param v is the vector to compute a distance to.
-   * @return the linear distance.
-   */
-  public double linearDistance(final Vector v) {
-    return Math.sqrt(linearDistanceSquared(v));
-  }
-
-  /**
-   * Compute the straight-line distance to a point described by the
-   * vector taken from the origin.
-   * Monotonically increasing for arc distances up to PI.
-   *
-   * @param x is the x part of the vector to compute a distance to.
-   * @param y is the y part of the vector to compute a distance to.
-   * @param z is the z part of the vector to compute a distance to.
-   * @return the linear distance.
-   */
-  public double linearDistance(final double x, final double y, final double z) {
-    return Math.sqrt(linearDistanceSquared(x, y, z));
-  }
-
-  /**
-   * Compute the square of the normal distance to a vector described by a
-   * vector taken from the origin.
-   * Monotonically increasing for arc distances up to PI/2.
-   *
-   * @param v is the vector to compute a distance to.
-   * @return the square of the normal distance.
-   */
-  public double normalDistanceSquared(final Vector v) {
-    double t = dotProduct(v);
-    double deltaX = this.x * t - v.x;
-    double deltaY = this.y * t - v.y;
-    double deltaZ = this.z * t - v.z;
-    return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
-  }
-
-  /**
-   * Compute the square of the normal distance to a vector described by a
-   * vector taken from the origin.
-   * Monotonically increasing for arc distances up to PI/2.
-   *
-   * @param x is the x part of the vector to compute a distance to.
-   * @param y is the y part of the vector to compute a distance to.
-   * @param z is the z part of the vector to compute a distance to.
-   * @return the square of the normal distance.
-   */
-  public double normalDistanceSquared(final double x, final double y, final double z) {
-    double t = dotProduct(x, y, z);
-    double deltaX = this.x * t - x;
-    double deltaY = this.y * t - y;
-    double deltaZ = this.z * t - z;
-    return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
-  }
-
-  /**
-   * Compute the normal (perpendicular) distance to a vector described by a
-   * vector taken from the origin.
-   * Monotonically increasing for arc distances up to PI/2.
-   *
-   * @param v is the vector to compute a distance to.
-   * @return the normal distance.
-   */
-  public double normalDistance(final Vector v) {
-    return Math.sqrt(normalDistanceSquared(v));
-  }
-
-  /**
-   * Compute the normal (perpendicular) distance to a vector described by a
-   * vector taken from the origin.
-   * Monotonically increasing for arc distances up to PI/2.
-   *
-   * @param x is the x part of the vector to compute a distance to.
-   * @param y is the y part of the vector to compute a distance to.
-   * @param z is the z part of the vector to compute a distance to.
-   * @return the normal distance.
-   */
-  public double normalDistance(final double x, final double y, final double z) {
-    return Math.sqrt(normalDistanceSquared(x, y, z));
-  }
-
-  /**
-   * Compute the magnitude of this vector.
-   *
-   * @return the magnitude.
-   */
-  public double magnitude() {
-    return magnitude(x,y,z);
-  }
-
-  /** Compute the desired magnitude of a unit vector projected to a given
-   * planet model.
-   * @param planetModel is the planet model.
-   * @param x is the unit vector x value.
-   * @param y is the unit vector y value.
-   * @param z is the unit vector z value.
-   * @return a magnitude value for that (x,y,z) that projects the vector onto the specified ellipsoid.
-   */
-  protected static double computeDesiredEllipsoidMagnitude(final PlanetModel planetModel, final double x, final double y, final double z) {
-    return 1.0 / Math.sqrt(x*x*planetModel.inverseAbSquared + y*y*planetModel.inverseAbSquared + z*z*planetModel.inverseCSquared);
-  }
-
-  /** Compute the desired magnitude of a unit vector projected to a given
-   * planet model.  The unit vector is specified only by a z value.
-   * @param planetModel is the planet model.
-   * @param z is the unit vector z value.
-   * @return a magnitude value for that z value that projects the vector onto the specified ellipsoid.
-   */
-  protected static double computeDesiredEllipsoidMagnitude(final PlanetModel planetModel, final double z) {
-    return 1.0 / Math.sqrt((1.0-z*z)*planetModel.inverseAbSquared + z*z*planetModel.inverseCSquared);
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof Vector))
-      return false;
-    Vector other = (Vector) o;
-    return (other.x == x && other.y == y && other.z == z);
-  }
-
-  @Override
-  public int hashCode() {
-    int result;
-    long temp;
-    temp = Double.doubleToLongBits(x);
-    result = (int) (temp ^ (temp >>> 32));
-    temp = Double.doubleToLongBits(y);
-    result = 31 * result + (int) (temp ^ (temp >>> 32));
-    temp = Double.doubleToLongBits(z);
-    result = 31 * result + (int) (temp ^ (temp >>> 32));
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "[X=" + x + ", Y=" + y + ", Z=" + z + "]";
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZBounds.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZBounds.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZBounds.java
deleted file mode 100644
index 22e324b..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZBounds.java
+++ /dev/null
@@ -1,267 +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.geo3d;
-
-/**
- * An object for accumulating XYZ bounds information.
- *
- * @lucene.experimental
- */
-public class XYZBounds implements Bounds {
-
-  /** A 'fudge factor', which is added to maximums and subtracted from minimums,
-   * in order to compensate for potential error deltas.  This would not be necessary
-   * except that our 'bounds' is defined as always equaling or exceeding the boundary
-   * of the shape, and we cannot guarantee that without making MINIMUM_RESOLUTION
-   * unacceptably large.
-   */
-  protected static final double FUDGE_FACTOR = Vector.MINIMUM_RESOLUTION * 2.0;
-  
-  /** Minimum x */
-  protected Double minX = null;
-  /** Maximum x */
-  protected Double maxX = null;
-  /** Minimum y */
-  protected Double minY = null;
-  /** Maximum y */
-  protected Double maxY = null;
-  /** Minimum z */
-  protected Double minZ = null;
-  /** Maximum z */
-  protected Double maxZ = null;
-  
-  /** Set to true if no longitude bounds can be stated */
-  protected boolean noLongitudeBound = false;
-  /** Set to true if no top latitude bound can be stated */
-  protected boolean noTopLatitudeBound = false;
-  /** Set to true if no bottom latitude bound can be stated */
-  protected boolean noBottomLatitudeBound = false;
-
-  /** Construct an empty bounds object */
-  public XYZBounds() {
-  }
-
-  // Accessor methods
-  
-  /** Return the minimum X value.
-   *@return minimum X value.
-   */
-  public Double getMinimumX() {
-    return minX;
-  }
-
-  /** Return the maximum X value.
-   *@return maximum X value.
-   */
-  public Double getMaximumX() {
-    return maxX;
-  }
-
-  /** Return the minimum Y value.
-   *@return minimum Y value.
-   */
-  public Double getMinimumY() {
-    return minY;
-  }
-
-  /** Return the maximum Y value.
-   *@return maximum Y value.
-   */
-  public Double getMaximumY() {
-    return maxY;
-  }
-  
-  /** Return the minimum Z value.
-   *@return minimum Z value.
-   */
-  public Double getMinimumZ() {
-    return minZ;
-  }
-
-  /** Return the maximum Z value.
-   *@return maximum Z value.
-   */
-  public Double getMaximumZ() {
-    return maxZ;
-  }
-
-  /** Return true if minX is as small as the planet model allows.
-   *@return true if minX has reached its bound.
-   */
-  public boolean isSmallestMinX(final PlanetModel planetModel) {
-    if (minX == null)
-      return false;
-    return minX - planetModel.getMinimumXValue() < Vector.MINIMUM_RESOLUTION;
-  }
-  
-  /** Return true if maxX is as large as the planet model allows.
-   *@return true if maxX has reached its bound.
-   */
-  public boolean isLargestMaxX(final PlanetModel planetModel) {
-    if (maxX == null)
-      return false;
-    return planetModel.getMaximumXValue() - maxX < Vector.MINIMUM_RESOLUTION;
-  }
-
-  /** Return true if minY is as small as the planet model allows.
-   *@return true if minY has reached its bound.
-   */
-  public boolean isSmallestMinY(final PlanetModel planetModel) {
-    if (minY == null)
-      return false;
-    return minY - planetModel.getMinimumYValue() < Vector.MINIMUM_RESOLUTION;
-  }
-  
-  /** Return true if maxY is as large as the planet model allows.
-   *@return true if maxY has reached its bound.
-   */
-  public boolean isLargestMaxY(final PlanetModel planetModel) {
-    if (maxY == null)
-      return false;
-    return planetModel.getMaximumYValue() - maxY < Vector.MINIMUM_RESOLUTION;
-  }
-  
-  /** Return true if minZ is as small as the planet model allows.
-   *@return true if minZ has reached its bound.
-   */
-  public boolean isSmallestMinZ(final PlanetModel planetModel) {
-    if (minZ == null)
-      return false;
-    return minZ - planetModel.getMinimumZValue() < Vector.MINIMUM_RESOLUTION;
-  }
-  
-  /** Return true if maxZ is as large as the planet model allows.
-   *@return true if maxZ has reached its bound.
-   */
-  public boolean isLargestMaxZ(final PlanetModel planetModel) {
-    if (maxZ == null)
-      return false;
-    return planetModel.getMaximumZValue() - maxZ < Vector.MINIMUM_RESOLUTION;
-  }
-
-  // Modification methods
-  
-  @Override
-  public Bounds addPlane(final PlanetModel planetModel, final Plane plane, final Membership... bounds) {
-    plane.recordBounds(planetModel, this, bounds);
-    return this;
-  }
-
-  /** Add a horizontal plane to the bounds description.
-   * This method should EITHER use the supplied latitude, OR use the supplied
-   * plane, depending on what is most efficient.
-   *@param planetModel is the planet model.
-   *@param latitude is the latitude.
-   *@param horizontalPlane is the plane.
-   *@param bounds are the constraints on the plane.
-   *@return updated Bounds object.
-   */
-  public Bounds addHorizontalPlane(final PlanetModel planetModel,
-    final double latitude,
-    final Plane horizontalPlane,
-    final Membership... bounds) {
-    return addPlane(planetModel, horizontalPlane, bounds);
-  }
-    
-  /** Add a vertical plane to the bounds description.
-   * This method should EITHER use the supplied longitude, OR use the supplied
-   * plane, depending on what is most efficient.
-   *@param planetModel is the planet model.
-   *@param longitude is the longitude.
-   *@param verticalPlane is the plane.
-   *@param bounds are the constraints on the plane.
-   *@return updated Bounds object.
-   */
-  public Bounds addVerticalPlane(final PlanetModel planetModel,
-    final double longitude,
-    final Plane verticalPlane,
-    final Membership... bounds) {
-    return addPlane(planetModel, verticalPlane, bounds);
-  }
-
-  @Override
-  public Bounds addXValue(final GeoPoint point) {
-    final double x = point.x;
-    final double small = x - FUDGE_FACTOR;
-    if (minX == null || minX > small) {
-      minX = new Double(small);
-    }
-    final double large = x + FUDGE_FACTOR;
-    if (maxX == null || maxX < large) {
-      maxX = new Double(large);
-    }
-    return this;
-  }
-
-  @Override
-  public Bounds addYValue(final GeoPoint point) {
-    final double y = point.y;
-    final double small = y - FUDGE_FACTOR;
-    if (minY == null || minY > small) {
-      minY = new Double(small);
-    }
-    final double large = y + FUDGE_FACTOR;
-    if (maxY == null || maxY < large) {
-      maxY = new Double(large);
-    }
-    return this;
-  }
-
-  @Override
-  public Bounds addZValue(final GeoPoint point) {
-    final double z = point.z;
-    final double small = z - FUDGE_FACTOR;
-    if (minZ == null || minZ > small) {
-      minZ = new Double(small);
-    }
-    final double large = z + FUDGE_FACTOR;
-    if (maxZ == null || maxZ < large) {
-      maxZ = new Double(large);
-    }
-    return this;
-  }
-
-  @Override
-  public Bounds addPoint(final GeoPoint point) {
-    return addXValue(point).addYValue(point).addZValue(point);
-  }
-
-  @Override
-  public Bounds isWide() {
-    // No specific thing we need to do.
-    return this;
-  }
-
-  @Override
-  public Bounds noLongitudeBound() {
-    // No specific thing we need to do.
-    return this;
-  }
-
-  @Override
-  public Bounds noTopLatitudeBound() {
-    // No specific thing we need to do.
-    return this;
-  }
-
-  @Override
-  public Bounds noBottomLatitudeBound() {
-    // No specific thing we need to do.
-    return this;
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolid.java
deleted file mode 100644
index ab46402..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolid.java
+++ /dev/null
@@ -1,26 +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.geo3d;
-
-/**
- * Interface for a family of 3D rectangles, bounded on six sides by X,Y,Z limits
- *
- * @lucene.internal
- */
-public interface XYZSolid extends GeoArea {
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolidFactory.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolidFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolidFactory.java
deleted file mode 100644
index 409ba86..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolidFactory.java
+++ /dev/null
@@ -1,67 +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.geo3d;
-
-/**
- * Factory for {@link org.apache.lucene.geo3d.XYZSolid}.
- *
- * @lucene.experimental
- */
-public class XYZSolidFactory {
-  private XYZSolidFactory() {
-  }
-
-  /**
-   * Create a XYZSolid of the right kind given (x,y,z) bounds.
-   * @param planetModel is the planet model
-   * @param minX is the min X boundary
-   * @param maxX is the max X boundary
-   * @param minY is the min Y boundary
-   * @param maxY is the max Y boundary
-   * @param minZ is the min Z boundary
-   * @param maxZ is the max Z boundary
-   */
-  public static XYZSolid makeXYZSolid(final PlanetModel planetModel, final double minX, final double maxX, final double minY, final double maxY, final double minZ, final double maxZ) {
-    if (Math.abs(maxX - minX) < Vector.MINIMUM_RESOLUTION) {
-      if (Math.abs(maxY - minY) < Vector.MINIMUM_RESOLUTION) {
-        if (Math.abs(maxZ - minZ) < Vector.MINIMUM_RESOLUTION) {
-          return new dXdYdZSolid(planetModel, (minX+maxX) * 0.5, (minY+maxY) * 0.5, minZ);
-        } else {
-          return new dXdYZSolid(planetModel, (minX+maxX) * 0.5, (minY+maxY) * 0.5, minZ, maxZ);
-        }
-      } else {
-        if (Math.abs(maxZ - minZ) < Vector.MINIMUM_RESOLUTION) {
-          return new dXYdZSolid(planetModel, (minX+maxX) * 0.5, minY, maxY, (minZ+maxZ) * 0.5);
-        } else {
-          return new dXYZSolid(planetModel, (minX+maxX) * 0.5, minY, maxY, minZ, maxZ);
-        }
-      }
-    }
-    if (Math.abs(maxY - minY) < Vector.MINIMUM_RESOLUTION) {
-      if (Math.abs(maxZ - minZ) < Vector.MINIMUM_RESOLUTION) {
-        return new XdYdZSolid(planetModel, minX, maxX, (minY+maxY) * 0.5, (minZ+maxZ) * 0.5);
-      } else {
-        return new XdYZSolid(planetModel, minX, maxX, (minY+maxY) * 0.5, minZ, maxZ);
-      }
-    }
-    if (Math.abs(maxZ - minZ) < Vector.MINIMUM_RESOLUTION) {
-      return new XYdZSolid(planetModel, minX, maxX, minY, maxY, (minZ+maxZ) * 0.5);
-    }
-    return new StandardXYZSolid(planetModel, minX, maxX, minY, maxY, minZ, maxZ);
-  }
-  
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYdZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYdZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYdZSolid.java
deleted file mode 100644
index e7cbe25..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYdZSolid.java
+++ /dev/null
@@ -1,213 +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.geo3d;
-
-/**
- * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in Z
- *
- * @lucene.internal
- */
-public class XYdZSolid extends BaseXYZSolid {
-
-  /** Min-X plane */
-  protected final SidedPlane minXPlane;
-  /** Max-X plane */
-  protected final SidedPlane maxXPlane;
-  /** Min-Y plane */
-  protected final SidedPlane minYPlane;
-  /** Max-Y plane */
-  protected final SidedPlane maxYPlane;
-  /** Z plane */
-  protected final Plane zPlane;
-  
-  /** These are the edge points of the shape, which are defined to be at least one point on
-   * each surface area boundary.  In the case of a solid, this includes points which represent
-   * the intersection of XYZ bounding planes and the planet, as well as points representing
-   * the intersection of single bounding planes with the planet itself.
-   */
-  protected final GeoPoint[] edgePoints;
-
-  /** Notable points for ZPlane */
-  protected final GeoPoint[] notableZPoints;
-
-  /**
-   * Sole constructor
-   *
-   *@param planetModel is the planet model.
-   *@param minX is the minimum X value.
-   *@param maxX is the maximum X value.
-   *@param minY is the minimum Y value.
-   *@param maxY is the maximum Y value.
-   *@param Z is the Z value.
-   */
-  public XYdZSolid(final PlanetModel planetModel,
-    final double minX,
-    final double maxX,
-    final double minY,
-    final double maxY,
-    final double Z) {
-    super(planetModel);
-    // Argument checking
-    if (maxX - minX < Vector.MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("X values in wrong order or identical");
-    if (maxY - minY < Vector.MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("Y values in wrong order or identical");
-
-    final double worldMinZ = planetModel.getMinimumZValue();
-    final double worldMaxZ = planetModel.getMaximumZValue();
-    
-    // Construct the planes
-    minXPlane = new SidedPlane(maxX,0.0,0.0,xUnitVector,-minX);
-    maxXPlane = new SidedPlane(minX,0.0,0.0,xUnitVector,-maxX);
-    minYPlane = new SidedPlane(0.0,maxY,0.0,yUnitVector,-minY);
-    maxYPlane = new SidedPlane(0.0,minY,0.0,yUnitVector,-maxY);
-    zPlane = new Plane(zUnitVector,-Z);
-      
-    // We need at least one point on the planet surface for each manifestation of the shape.
-    // There can be up to 2 (on opposite sides of the world).  But we have to go through
-    // 4 combinations of adjacent planes in order to find out if any have 2 intersection solution.
-    // Typically, this requires 4 square root operations. 
-    final GeoPoint[] minXZ = minXPlane.findIntersections(planetModel,zPlane,maxXPlane,minYPlane,maxYPlane);
-    final GeoPoint[] maxXZ = maxXPlane.findIntersections(planetModel,zPlane,minXPlane,minYPlane,maxYPlane);
-    final GeoPoint[] minYZ = minYPlane.findIntersections(planetModel,zPlane,maxYPlane,minXPlane,maxXPlane);
-    final GeoPoint[] maxYZ = maxYPlane.findIntersections(planetModel,zPlane,minYPlane,minXPlane,maxXPlane);
-      
-    notableZPoints = glueTogether(minXZ, maxXZ, minYZ, maxYZ);
-
-    // Now, compute the edge points.
-    // This is the trickiest part of setting up an XYZSolid.  We've computed intersections already, so
-    // we'll start there.  We know that at most there will be two disconnected shapes on the planet surface.
-    // But there's also a case where exactly one plane slices through the world, and none of the bounding plane
-    // intersections do.  Thus, if we don't find any of the edge intersection cases, we have to look for that last case.
-      
-    // If we still haven't encountered anything, we need to look at single-plane/world intersections.
-    // We detect these by looking at the world model and noting its x, y, and z bounds.
-    // The cases we are looking for are when the four corner points for any given
-    // plane are all outside of the world, AND that plane intersects the world.
-    // There are four corner points all told; we must evaluate these WRT the planet surface.
-    final boolean minXminYZ = planetModel.pointOutside(minX, minY, Z);
-    final boolean minXmaxYZ = planetModel.pointOutside(minX, maxY, Z);
-    final boolean maxXminYZ = planetModel.pointOutside(maxX, minY, Z);
-    final boolean maxXmaxYZ = planetModel.pointOutside(maxX, maxY, Z);
-
-    final GeoPoint[] zEdges;
-    if (Z - worldMinZ >= -Vector.MINIMUM_RESOLUTION && Z - worldMaxZ <= Vector.MINIMUM_RESOLUTION &&
-      minX < 0.0 && maxX > 0.0 && minY < 0.0 && maxY > 0.0 &&
-      minXminYZ && minXmaxYZ && maxXminYZ && maxXmaxYZ) {
-      // Find any point on the minZ plane that intersects the world
-      // First construct a perpendicular plane that will allow us to find a sample point.
-      // This plane is vertical and goes through the points (0,0,0) and (1,0,0)
-      // Then use it to compute a sample point.
-      final GeoPoint intPoint = zPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
-      if (intPoint != null) {
-        zEdges = new GeoPoint[]{intPoint};
-      } else {
-        zEdges = EMPTY_POINTS;
-      }
-    } else {
-      zEdges= EMPTY_POINTS;
-    }
-
-    this.edgePoints = glueTogether(minXZ, maxXZ, minYZ, maxYZ, zEdges);
-  }
-
-  @Override
-  protected GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-  
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return minXPlane.isWithin(x, y, z) &&
-      maxXPlane.isWithin(x, y, z) &&
-      minYPlane.isWithin(x, y, z) &&
-      maxYPlane.isWithin(x, y, z) &&
-      zPlane.evaluateIsZero(x, y, z);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    
-    //System.err.println(this+" getrelationship with "+path);
-    final int insideRectangle = isShapeInsideArea(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some inside");
-      return OVERLAPS;
-    }
-
-    // Figure out if the entire XYZArea is contained by the shape.
-    final int insideShape = isAreaInsideShape(path);
-    if (insideShape == SOME_INSIDE) {
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
-      //System.err.println(" inside of each other");
-      return OVERLAPS;
-    }
-
-    if (path.intersects(zPlane, notableZPoints, minXPlane, maxXPlane, minYPlane, maxYPlane)) {
-      //System.err.println(" edges intersect");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      //System.err.println(" shape inside rectangle");
-      return WITHIN;
-    }
-
-    if (insideShape == ALL_INSIDE) {
-      //System.err.println(" shape contains rectangle");
-      return CONTAINS;
-    }
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof XYdZSolid))
-      return false;
-    XYdZSolid other = (XYdZSolid) o;
-    if (!super.equals(other)) {
-      return false;
-    }
-    return other.minXPlane.equals(minXPlane) &&
-      other.maxXPlane.equals(maxXPlane) &&
-      other.minYPlane.equals(minYPlane) &&
-      other.maxYPlane.equals(maxYPlane) &&
-      other.zPlane.equals(zPlane);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result  + minXPlane.hashCode();
-    result = 31 * result  + maxXPlane.hashCode();
-    result = 31 * result  + minYPlane.hashCode();
-    result = 31 * result  + maxYPlane.hashCode();
-    result = 31 * result  + zPlane.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "XYdZSolid: {planetmodel="+planetModel+", minXplane="+minXPlane+", maxXplane="+maxXPlane+", minYplane="+minYPlane+", maxYplane="+maxYPlane+", zplane="+zPlane+"}";
-  }
-  
-}
-  


[12/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 0093e26)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/LinearDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/LinearDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/LinearDistance.java
deleted file mode 100644
index 9cbedba..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/LinearDistance.java
+++ /dev/null
@@ -1,56 +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.geo3d;
-
-/**
- * Linear distance computation style.
- *
- * @lucene.experimental
- */
-public class LinearDistance implements DistanceStyle {
-  
-  /** A convenient instance */
-  public final static LinearDistance INSTANCE = new LinearDistance();
-  
-  /** Constructor.
-   */
-  public LinearDistance() {
-  }
-  
-  @Override
-  public double computeDistance(final GeoPoint point1, final GeoPoint point2) {
-    return point1.linearDistance(point2);
-  }
-  
-  @Override
-  public double computeDistance(final GeoPoint point1, final double x2, final double y2, final double z2) {
-    return point1.linearDistance(x2,y2,z2);
-  }
-
-  @Override
-  public double computeDistance(final PlanetModel planetModel, final Plane plane, final GeoPoint point, final Membership... bounds) {
-    return plane.linearDistance(planetModel, point, bounds);
-  }
-  
-  @Override
-  public double computeDistance(final PlanetModel planetModel, final Plane plane, final double x, final double y, final double z, final Membership... bounds) {
-    return plane.linearDistance(planetModel, x,y,z, bounds);
-  }
-
-}
-
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/LinearSquaredDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/LinearSquaredDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/LinearSquaredDistance.java
deleted file mode 100644
index 028d3c4..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/LinearSquaredDistance.java
+++ /dev/null
@@ -1,56 +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.geo3d;
-
-/**
- * Linear squared distance computation style.
- *
- * @lucene.experimental
- */
-public class LinearSquaredDistance implements DistanceStyle {
-  
-  /** A convenient instance */
-  public final static LinearSquaredDistance INSTANCE = new LinearSquaredDistance();
-  
-  /** Constructor.
-   */
-  public LinearSquaredDistance() {
-  }
-  
-  @Override
-  public double computeDistance(final GeoPoint point1, final GeoPoint point2) {
-    return point1.linearDistanceSquared(point2);
-  }
-  
-  @Override
-  public double computeDistance(final GeoPoint point1, final double x2, final double y2, final double z2) {
-    return point1.linearDistanceSquared(x2,y2,z2);
-  }
-
-  @Override
-  public double computeDistance(final PlanetModel planetModel, final Plane plane, final GeoPoint point, final Membership... bounds) {
-    return plane.linearDistanceSquared(planetModel, point, bounds);
-  }
-  
-  @Override
-  public double computeDistance(final PlanetModel planetModel, final Plane plane, final double x, final double y, final double z, final Membership... bounds) {
-    return plane.linearDistanceSquared(planetModel, x,y,z, bounds);
-  }
-
-}
-
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Membership.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Membership.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Membership.java
deleted file mode 100755
index 3ca6b09..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Membership.java
+++ /dev/null
@@ -1,46 +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.geo3d;
-
-/**
- * Implemented by Geo3D shapes that can calculate if a point is within it or not.
- *
- * @lucene.experimental
- */
-public interface Membership {
-
-  /**
-   * Check if a point is within this shape.
-   *
-   * @param point is the point to check.
-   * @return true if the point is within this shape
-   */
-  public default boolean isWithin(final Vector point) {
-    return isWithin(point.x, point.y, point.z);
-  }
-
-  /**
-   * Check if a point is within this shape.
-   *
-   * @param x is x coordinate of point to check.
-   * @param y is y coordinate of point to check.
-   * @param z is z coordinate of point to check.
-   * @return true if the point is within this shape
-   */
-  public boolean isWithin(final double x, final double y, final double z);
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/NormalDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/NormalDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/NormalDistance.java
deleted file mode 100644
index cdac0d2..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/NormalDistance.java
+++ /dev/null
@@ -1,56 +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.geo3d;
-
-/**
- * Normal distance computation style.
- *
- * @lucene.experimental
- */
-public class NormalDistance implements DistanceStyle {
-  
-  /** A convenient instance */
-  public final static NormalDistance INSTANCE = new NormalDistance();
-  
-  /** Constructor.
-   */
-  public NormalDistance() {
-  }
-  
-  @Override
-  public double computeDistance(final GeoPoint point1, final GeoPoint point2) {
-    return point1.normalDistance(point2);
-  }
-  
-  @Override
-  public double computeDistance(final GeoPoint point1, final double x2, final double y2, final double z2) {
-    return point1.normalDistance(x2,y2,z2);
-  }
-
-  @Override
-  public double computeDistance(final PlanetModel planetModel, final Plane plane, final GeoPoint point, final Membership... bounds) {
-    return plane.normalDistance(point, bounds);
-  }
-  
-  @Override
-  public double computeDistance(final PlanetModel planetModel, final Plane plane, final double x, final double y, final double z, final Membership... bounds) {
-    return plane.normalDistance(x,y,z, bounds);
-  }
-
-}
-
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/NormalSquaredDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/NormalSquaredDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/NormalSquaredDistance.java
deleted file mode 100644
index 035fd40..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/NormalSquaredDistance.java
+++ /dev/null
@@ -1,56 +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.geo3d;
-
-/**
- * Normal squared distance computation style.
- *
- * @lucene.experimental
- */
-public class NormalSquaredDistance implements DistanceStyle {
-  
-  /** A convenient instance */
-  public final static NormalSquaredDistance INSTANCE = new NormalSquaredDistance();
-  
-  /** Constructor.
-   */
-  public NormalSquaredDistance() {
-  }
-  
-  @Override
-  public double computeDistance(final GeoPoint point1, final GeoPoint point2) {
-    return point1.normalDistanceSquared(point2);
-  }
-  
-  @Override
-  public double computeDistance(final GeoPoint point1, final double x2, final double y2, final double z2) {
-    return point1.normalDistanceSquared(x2,y2,z2);
-  }
-
-  @Override
-  public double computeDistance(final PlanetModel planetModel, final Plane plane, final GeoPoint point, final Membership... bounds) {
-    return plane.normalDistanceSquared(point, bounds);
-  }
-  
-  @Override
-  public double computeDistance(final PlanetModel planetModel, final Plane plane, final double x, final double y, final double z, final Membership... bounds) {
-    return plane.normalDistanceSquared(x,y,z, bounds);
-  }
-
-}
-
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Plane.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Plane.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Plane.java
deleted file mode 100755
index 07d0c5b..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Plane.java
+++ /dev/null
@@ -1,1657 +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.geo3d;
-
-/**
- * We know about three kinds of planes.  First kind: general plain through two points and origin
- * Second kind: horizontal plane at specified height.  Third kind: vertical plane with specified x and y value, through origin.
- *
- * @lucene.experimental
- */
-public class Plane extends Vector {
-  /** An array with no points in it */
-  protected final static GeoPoint[] NO_POINTS = new GeoPoint[0];
-  /** An array with no bounds in it */
-  protected final static Membership[] NO_BOUNDS = new Membership[0];
-  /** A vertical plane normal to the Y axis */
-  protected final static Plane normalYPlane = new Plane(0.0,1.0,0.0,0.0);
-  /** A vertical plane normal to the X axis */
-  protected final static Plane normalXPlane = new Plane(1.0,0.0,0.0,0.0);
-  /** A vertical plane normal to the Z axis */
-  protected final static Plane normalZPlane = new Plane(0.0,0.0,1.0,0.0);
-
-  /** Ax + By + Cz + D = 0 */
-  public final double D;
-
-  /**
-   * Construct a plane with all four coefficients defined.
-   *@param A is A
-   *@param B is B
-   *@param C is C
-   *@param D is D
-   */
-  public Plane(final double A, final double B, final double C, final double D) {
-    super(A, B, C);
-    this.D = D;
-  }
-
-  /**
-   * Construct a plane through two points and origin.
-   *
-   * @param A is the first point (origin based).
-   * @param B is the second point (origin based).
-   */
-  public Plane(final Vector A, final Vector B) {
-    super(A, B);
-    D = 0.0;
-  }
-
-  /**
-   * Construct a horizontal plane at a specified Z.
-   *
-   * @param planetModel is the planet model.
-   * @param sinLat is the sin(latitude).
-   */
-  public Plane(final PlanetModel planetModel, final double sinLat) {
-    super(0.0, 0.0, 1.0);
-    D = -sinLat * computeDesiredEllipsoidMagnitude(planetModel, sinLat);
-  }
-
-  /**
-   * Construct a vertical plane through a specified
-   * x, y and origin.
-   *
-   * @param x is the specified x value.
-   * @param y is the specified y value.
-   */
-  public Plane(final double x, final double y) {
-    super(y, -x, 0.0);
-    D = 0.0;
-  }
-
-  /**
-   * Construct a plane with a specific vector, and D offset
-   * from origin.
-   * @param v is the normal vector.
-   * @param D is the D offset from the origin.
-   */
-  public Plane(final Vector v, final double D) {
-    super(v.x, v.y, v.z);
-    this.D = D;
-  }
-
-  /** Construct the most accurate normalized plane through an x-y point and including the Z axis.
-   * If none of the points can determine the plane, return null.
-   * @param planePoints is a set of points to choose from.  The best one for constructing the most precise plane is picked.
-   * @return the plane
-   */
-  public static Plane constructNormalizedZPlane(final Vector... planePoints) {
-    // Pick the best one (with the greatest x-y distance)
-    double bestDistance = 0.0;
-    Vector bestPoint = null;
-    for (final Vector point : planePoints) {
-      final double pointDist = point.x * point.x + point.y * point.y;
-      if (pointDist > bestDistance) {
-        bestDistance = pointDist;
-        bestPoint = point;
-      }
-    }
-    return constructNormalizedZPlane(bestPoint.x, bestPoint.y);
-  }
-
-  /** Construct the most accurate normalized plane through an x-z point and including the Y axis.
-   * If none of the points can determine the plane, return null.
-   * @param planePoints is a set of points to choose from.  The best one for constructing the most precise plane is picked.
-   * @return the plane
-   */
-  public static Plane constructNormalizedYPlane(final Vector... planePoints) {
-    // Pick the best one (with the greatest x-z distance)
-    double bestDistance = 0.0;
-    Vector bestPoint = null;
-    for (final Vector point : planePoints) {
-      final double pointDist = point.x * point.x + point.z * point.z;
-      if (pointDist > bestDistance) {
-        bestDistance = pointDist;
-        bestPoint = point;
-      }
-    }
-    return constructNormalizedYPlane(bestPoint.x, bestPoint.z, 0.0);
-  }
-
-  /** Construct the most accurate normalized plane through an y-z point and including the X axis.
-   * If none of the points can determine the plane, return null.
-   * @param planePoints is a set of points to choose from.  The best one for constructing the most precise plane is picked.
-   * @return the plane
-   */
-  public static Plane constructNormalizedXPlane(final Vector... planePoints) {
-    // Pick the best one (with the greatest y-z distance)
-    double bestDistance = 0.0;
-    Vector bestPoint = null;
-    for (final Vector point : planePoints) {
-      final double pointDist = point.y * point.y + point.z * point.z;
-      if (pointDist > bestDistance) {
-        bestDistance = pointDist;
-        bestPoint = point;
-      }
-    }
-    return constructNormalizedXPlane(bestPoint.y, bestPoint.z, 0.0);
-  }
-
-  /** Construct a normalized plane through an x-y point and including the Z axis.
-   * If the x-y point is at (0,0), return null.
-   * @param x is the x value.
-   * @param y is the y value.
-   * @return a plane passing through the Z axis and (x,y,0).
-   */
-  public static Plane constructNormalizedZPlane(final double x, final double y) {
-    if (Math.abs(x) < MINIMUM_RESOLUTION && Math.abs(y) < MINIMUM_RESOLUTION)
-      return null;
-    final double denom = 1.0 / Math.sqrt(x*x + y*y);
-    return new Plane(y * denom, -x * denom, 0.0, 0.0);
-  }
-
-  /** Construct a normalized plane through an x-z point and parallel to the Y axis.
-   * If the x-z point is at (0,0), return null.
-   * @param x is the x value.
-   * @param z is the z value.
-   * @param DValue is the offset from the origin for the plane.
-   * @return a plane parallel to the Y axis and perpendicular to the x and z values given.
-   */
-  public static Plane constructNormalizedYPlane(final double x, final double z, final double DValue) {
-    if (Math.abs(x) < MINIMUM_RESOLUTION && Math.abs(z) < MINIMUM_RESOLUTION)
-      return null;
-    final double denom = 1.0 / Math.sqrt(x*x + z*z);
-    return new Plane(z * denom, 0.0, -x * denom, DValue);
-  }
-
-  /** Construct a normalized plane through a y-z point and parallel to the X axis.
-   * If the y-z point is at (0,0), return null.
-   * @param y is the y value.
-   * @param z is the z value.
-   * @param DValue is the offset from the origin for the plane.
-   * @return a plane parallel to the X axis and perpendicular to the y and z values given.
-   */
-  public static Plane constructNormalizedXPlane(final double y, final double z, final double DValue) {
-    if (Math.abs(y) < MINIMUM_RESOLUTION && Math.abs(z) < MINIMUM_RESOLUTION)
-      return null;
-    final double denom = 1.0 / Math.sqrt(y*y + z*z);
-    return new Plane(0.0, z * denom, -y * denom, DValue);
-  }
-  
-  /**
-   * Evaluate the plane equation for a given point, as represented
-   * by a vector.
-   *
-   * @param v is the vector.
-   * @return the result of the evaluation.
-   */
-  public double evaluate(final Vector v) {
-    return dotProduct(v) + D;
-  }
-
-  /**
-   * Evaluate the plane equation for a given point, as represented
-   * by a vector.
-   * @param x is the x value.
-   * @param y is the y value.
-   * @param z is the z value.
-   * @return the result of the evaluation.
-   */
-  public double evaluate(final double x, final double y, final double z) {
-    return dotProduct(x, y, z) + D;
-  }
-
-  /**
-   * Evaluate the plane equation for a given point, as represented
-   * by a vector.
-   *
-   * @param v is the vector.
-   * @return true if the result is on the plane.
-   */
-  public boolean evaluateIsZero(final Vector v) {
-    return Math.abs(evaluate(v)) < MINIMUM_RESOLUTION;
-  }
-
-  /**
-   * Evaluate the plane equation for a given point, as represented
-   * by a vector.
-   *
-   * @param x is the x value.
-   * @param y is the y value.
-   * @param z is the z value.
-   * @return true if the result is on the plane.
-   */
-  public boolean evaluateIsZero(final double x, final double y, final double z) {
-    return Math.abs(evaluate(x, y, z)) < MINIMUM_RESOLUTION;
-  }
-
-  /**
-   * Build a normalized plane, so that the vector is normalized.
-   *
-   * @return the normalized plane object, or null if the plane is indeterminate.
-   */
-  public Plane normalize() {
-    Vector normVect = super.normalize();
-    if (normVect == null)
-      return null;
-    return new Plane(normVect, this.D);
-  }
-
-  /** Compute arc distance from plane to a vector expressed with a {@link GeoPoint}.
-   *  @see #arcDistance(PlanetModel, double, double, double, Membership...) */
-  public double arcDistance(final PlanetModel planetModel, final GeoPoint v, final Membership... bounds) {
-    return arcDistance(planetModel, v.x, v.y, v.z, bounds);
-  }
-    
-  /**
-   * Compute arc distance from plane to a vector.
-   * @param planetModel is the planet model.
-   * @param x is the x vector value.
-   * @param y is the y vector value.
-   * @param z is the z vector value.
-   * @param bounds are the bounds which constrain the intersection point.
-   * @return the arc distance.
-   */
-  public double arcDistance(final PlanetModel planetModel, final double x, final double y, final double z, final Membership... bounds) {
-
-    if (evaluateIsZero(x,y,z)) {
-      if (meetsAllBounds(x,y,z, bounds))
-        return 0.0;
-      return Double.MAX_VALUE;
-    }
-    
-    // First, compute the perpendicular plane.
-    final Plane perpPlane = new Plane(this.y * z - this.z * y, this.z * x - this.x * z, this.x * y - this.y * x, 0.0);
-
-    // We need to compute the intersection of two planes on the geo surface: this one, and its perpendicular.
-    // Then, we need to choose which of the two points we want to compute the distance to.  We pick the
-    // shorter distance always.
-    
-    final GeoPoint[] intersectionPoints = findIntersections(planetModel, perpPlane);
-    
-    // For each point, compute a linear distance, and take the minimum of them
-    double minDistance = Double.MAX_VALUE;
-    
-    for (final GeoPoint intersectionPoint : intersectionPoints) {
-      if (meetsAllBounds(intersectionPoint, bounds)) {
-        final double theDistance = intersectionPoint.arcDistance(x,y,z);
-        if (theDistance < minDistance) {
-          minDistance = theDistance;
-        }
-      }
-    }
-    return minDistance;
-
-  }
-
-  /**
-   * Compute normal distance from plane to a vector.
-   * @param v is the vector.
-   * @param bounds are the bounds which constrain the intersection point.
-   * @return the normal distance.
-   */
-  public double normalDistance(final Vector v, final Membership... bounds) {
-    return normalDistance(v.x, v.y, v.z, bounds);
-  }
-    
-  /**
-   * Compute normal distance from plane to a vector.
-   * @param x is the vector x.
-   * @param y is the vector y.
-   * @param z is the vector z.
-   * @param bounds are the bounds which constrain the intersection point.
-   * @return the normal distance.
-   */
-  public double normalDistance(final double x, final double y, final double z, final Membership... bounds) {
-
-    final double dist = evaluate(x,y,z);
-    final double perpX = x - dist * this.x;
-    final double perpY = y - dist * this.y;
-    final double perpZ = z - dist * this.z;
-
-    if (!meetsAllBounds(perpX, perpY, perpZ, bounds)) {
-      return Double.MAX_VALUE;
-    }
-    
-    return Math.abs(dist);
-  }
-  
-  /**
-   * Compute normal distance squared from plane to a vector.
-   * @param v is the vector.
-   * @param bounds are the bounds which constrain the intersection point.
-   * @return the normal distance squared.
-   */
-  public double normalDistanceSquared(final Vector v, final Membership... bounds) {
-    return normalDistanceSquared(v.x, v.y, v.z, bounds);
-  }
-  
-  /**
-   * Compute normal distance squared from plane to a vector.
-   * @param x is the vector x.
-   * @param y is the vector y.
-   * @param z is the vector z.
-   * @param bounds are the bounds which constrain the intersection point.
-   * @return the normal distance squared.
-   */
-  public double normalDistanceSquared(final double x, final double y, final double z, final Membership... bounds) {
-    final double normal = normalDistance(x,y,z,bounds);
-    if (normal == Double.MAX_VALUE)
-      return normal;
-    return normal * normal;
-  }
-
-  /**
-   * Compute linear distance from plane to a vector.  This is defined
-   * as the distance from the given point to the nearest intersection of 
-   * this plane with the planet surface.
-   * @param planetModel is the planet model.
-   * @param v is the point.
-   * @param bounds are the bounds which constrain the intersection point.
-   * @return the linear distance.
-   */
-  public double linearDistance(final PlanetModel planetModel, final GeoPoint v, final Membership... bounds) {
-    return linearDistance(planetModel, v.x, v.y, v.z, bounds);
-  }
-    
-  /**
-   * Compute linear distance from plane to a vector.  This is defined
-   * as the distance from the given point to the nearest intersection of 
-   * this plane with the planet surface.
-   * @param planetModel is the planet model.
-   * @param x is the vector x.
-   * @param y is the vector y.
-   * @param z is the vector z.
-   * @param bounds are the bounds which constrain the intersection point.
-   * @return the linear distance.
-   */
-  public double linearDistance(final PlanetModel planetModel, final double x, final double y, final double z, final Membership... bounds) {
-    if (evaluateIsZero(x,y,z)) {
-      if (meetsAllBounds(x,y,z, bounds))
-        return 0.0;
-      return Double.MAX_VALUE;
-    }
-    
-    // First, compute the perpendicular plane.
-    final Plane perpPlane = new Plane(this.y * z - this.z * y, this.z * x - this.x * z, this.x * y - this.y * x, 0.0);
-
-    // We need to compute the intersection of two planes on the geo surface: this one, and its perpendicular.
-    // Then, we need to choose which of the two points we want to compute the distance to.  We pick the
-    // shorter distance always.
-    
-    final GeoPoint[] intersectionPoints = findIntersections(planetModel, perpPlane);
-    
-    // For each point, compute a linear distance, and take the minimum of them
-    double minDistance = Double.MAX_VALUE;
-    
-    for (final GeoPoint intersectionPoint : intersectionPoints) {
-      if (meetsAllBounds(intersectionPoint, bounds)) {
-        final double theDistance = intersectionPoint.linearDistance(x,y,z);
-        if (theDistance < minDistance) {
-          minDistance = theDistance;
-        }
-      }
-    }
-    return minDistance;
-  }
-      
-  /**
-   * Compute linear distance squared from plane to a vector.  This is defined
-   * as the distance from the given point to the nearest intersection of 
-   * this plane with the planet surface.
-   * @param planetModel is the planet model.
-   * @param v is the point.
-   * @param bounds are the bounds which constrain the intersection point.
-   * @return the linear distance squared.
-   */
-  public double linearDistanceSquared(final PlanetModel planetModel, final GeoPoint v, final Membership... bounds) {
-    return linearDistanceSquared(planetModel, v.x, v.y, v.z, bounds);
-  }
-  
-  /**
-   * Compute linear distance squared from plane to a vector.  This is defined
-   * as the distance from the given point to the nearest intersection of 
-   * this plane with the planet surface.
-   * @param planetModel is the planet model.
-   * @param x is the vector x.
-   * @param y is the vector y.
-   * @param z is the vector z.
-   * @param bounds are the bounds which constrain the intersection point.
-   * @return the linear distance squared.
-   */
-  public double linearDistanceSquared(final PlanetModel planetModel, final double x, final double y, final double z, final Membership... bounds) {
-    final double linearDistance = linearDistance(planetModel, x, y, z, bounds);
-    return linearDistance * linearDistance;
-  }
-
-  /**
-   * Find points on the boundary of the intersection of a plane and the unit sphere,
-   * given a starting point, and ending point, and a list of proportions of the arc (e.g. 0.25, 0.5, 0.75).
-   * The angle between the starting point and ending point is assumed to be less than pi.
-   * @param start is the start point.
-   * @param end is the end point.
-   * @param proportions is an array of fractional proportions measured between start and end.
-   * @return an array of points corresponding to the proportions passed in.
-   */
-  public GeoPoint[] interpolate(final GeoPoint start, final GeoPoint end, final double[] proportions) {
-    // Steps:
-    // (1) Translate (x0,y0,z0) of endpoints into origin-centered place:
-    // x1 = x0 + D*A
-    // y1 = y0 + D*B
-    // z1 = z0 + D*C
-    // (2) Rotate counterclockwise in x-y:
-    // ra = -atan2(B,A)
-    // x2 = x1 cos ra - y1 sin ra
-    // y2 = x1 sin ra + y1 cos ra
-    // z2 = z1
-    // Faster:
-    // cos ra = A/sqrt(A^2+B^2+C^2)
-    // sin ra = -B/sqrt(A^2+B^2+C^2)
-    // cos (-ra) = A/sqrt(A^2+B^2+C^2)
-    // sin (-ra) = B/sqrt(A^2+B^2+C^2)
-    // (3) Rotate clockwise in x-z:
-    // ha = pi/2 - asin(C/sqrt(A^2+B^2+C^2))
-    // x3 = x2 cos ha - z2 sin ha
-    // y3 = y2
-    // z3 = x2 sin ha + z2 cos ha
-    // At this point, z3 should be zero.
-    // Faster:
-    // sin(ha) = cos(asin(C/sqrt(A^2+B^2+C^2))) = sqrt(1 - C^2/(A^2+B^2+C^2)) = sqrt(A^2+B^2)/sqrt(A^2+B^2+C^2)
-    // cos(ha) = sin(asin(C/sqrt(A^2+B^2+C^2))) = C/sqrt(A^2+B^2+C^2)
-    // (4) Compute interpolations by getting longitudes of original points
-    // la = atan2(y3,x3)
-    // (5) Rotate new points (xN0, yN0, zN0) counter-clockwise in x-z:
-    // ha = -(pi - asin(C/sqrt(A^2+B^2+C^2)))
-    // xN1 = xN0 cos ha - zN0 sin ha
-    // yN1 = yN0
-    // zN1 = xN0 sin ha + zN0 cos ha
-    // (6) Rotate new points clockwise in x-y:
-    // ra = atan2(B,A)
-    // xN2 = xN1 cos ra - yN1 sin ra
-    // yN2 = xN1 sin ra + yN1 cos ra
-    // zN2 = zN1
-    // (7) Translate new points:
-    // xN3 = xN2 - D*A
-    // yN3 = yN2 - D*B
-    // zN3 = zN2 - D*C
-
-    // First, calculate the angles and their sin/cos values
-    double A = x;
-    double B = y;
-    double C = z;
-
-    // Translation amounts
-    final double transX = -D * A;
-    final double transY = -D * B;
-    final double transZ = -D * C;
-
-    double cosRA;
-    double sinRA;
-    double cosHA;
-    double sinHA;
-
-    double magnitude = magnitude();
-    if (magnitude >= MINIMUM_RESOLUTION) {
-      final double denom = 1.0 / magnitude;
-      A *= denom;
-      B *= denom;
-      C *= denom;
-
-      // cos ra = A/sqrt(A^2+B^2+C^2)
-      // sin ra = -B/sqrt(A^2+B^2+C^2)
-      // cos (-ra) = A/sqrt(A^2+B^2+C^2)
-      // sin (-ra) = B/sqrt(A^2+B^2+C^2)
-      final double xyMagnitude = Math.sqrt(A * A + B * B);
-      if (xyMagnitude >= MINIMUM_RESOLUTION) {
-        final double xyDenom = 1.0 / xyMagnitude;
-        cosRA = A * xyDenom;
-        sinRA = -B * xyDenom;
-      } else {
-        cosRA = 1.0;
-        sinRA = 0.0;
-      }
-
-      // sin(ha) = cos(asin(C/sqrt(A^2+B^2+C^2))) = sqrt(1 - C^2/(A^2+B^2+C^2)) = sqrt(A^2+B^2)/sqrt(A^2+B^2+C^2)
-      // cos(ha) = sin(asin(C/sqrt(A^2+B^2+C^2))) = C/sqrt(A^2+B^2+C^2)
-      sinHA = xyMagnitude;
-      cosHA = C;
-    } else {
-      cosRA = 1.0;
-      sinRA = 0.0;
-      cosHA = 1.0;
-      sinHA = 0.0;
-    }
-
-    // Forward-translate the start and end points
-    final Vector modifiedStart = modify(start, transX, transY, transZ, sinRA, cosRA, sinHA, cosHA);
-    final Vector modifiedEnd = modify(end, transX, transY, transZ, sinRA, cosRA, sinHA, cosHA);
-    if (Math.abs(modifiedStart.z) >= MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("Start point was not on plane: " + modifiedStart.z);
-    if (Math.abs(modifiedEnd.z) >= MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("End point was not on plane: " + modifiedEnd.z);
-
-    // Compute the angular distance between start and end point
-    final double startAngle = Math.atan2(modifiedStart.y, modifiedStart.x);
-    final double endAngle = Math.atan2(modifiedEnd.y, modifiedEnd.x);
-
-    final double startMagnitude = Math.sqrt(modifiedStart.x * modifiedStart.x + modifiedStart.y * modifiedStart.y);
-    double delta;
-
-    double newEndAngle = endAngle;
-    while (newEndAngle < startAngle) {
-      newEndAngle += Math.PI * 2.0;
-    }
-
-    if (newEndAngle - startAngle <= Math.PI) {
-      delta = newEndAngle - startAngle;
-    } else {
-      double newStartAngle = startAngle;
-      while (newStartAngle < endAngle) {
-        newStartAngle += Math.PI * 2.0;
-      }
-      delta = newStartAngle - endAngle;
-    }
-
-    final GeoPoint[] returnValues = new GeoPoint[proportions.length];
-    for (int i = 0; i < returnValues.length; i++) {
-      final double newAngle = startAngle + proportions[i] * delta;
-      final double sinNewAngle = Math.sin(newAngle);
-      final double cosNewAngle = Math.cos(newAngle);
-      final Vector newVector = new Vector(cosNewAngle * startMagnitude, sinNewAngle * startMagnitude, 0.0);
-      returnValues[i] = reverseModify(newVector, transX, transY, transZ, sinRA, cosRA, sinHA, cosHA);
-    }
-
-    return returnValues;
-  }
-
-  /**
-   * Modify a point to produce a vector in translated/rotated space.
-   * @param start is the start point.
-   * @param transX is the translation x value.
-   * @param transY is the translation y value.
-   * @param transZ is the translation z value.
-   * @param sinRA is the sine of the ascension angle.
-   * @param cosRA is the cosine of the ascension angle.
-   * @param sinHA is the sine of the height angle.
-   * @param cosHA is the cosine of the height angle.
-   * @return the modified point.
-   */
-  protected static Vector modify(final GeoPoint start, final double transX, final double transY, final double transZ,
-                                 final double sinRA, final double cosRA, final double sinHA, final double cosHA) {
-    return start.translate(transX, transY, transZ).rotateXY(sinRA, cosRA).rotateXZ(sinHA, cosHA);
-  }
-
-  /**
-   * Reverse modify a point to produce a GeoPoint in normal space.
-   * @param point is the translated point.
-   * @param transX is the translation x value.
-   * @param transY is the translation y value.
-   * @param transZ is the translation z value.
-   * @param sinRA is the sine of the ascension angle.
-   * @param cosRA is the cosine of the ascension angle.
-   * @param sinHA is the sine of the height angle.
-   * @param cosHA is the cosine of the height angle.
-   * @return the original point.
-   */
-  protected static GeoPoint reverseModify(final Vector point, final double transX, final double transY, final double transZ,
-                                          final double sinRA, final double cosRA, final double sinHA, final double cosHA) {
-    final Vector result = point.rotateXZ(-sinHA, cosHA).rotateXY(-sinRA, cosRA).translate(-transX, -transY, -transZ);
-    return new GeoPoint(result.x, result.y, result.z);
-  }
-
-  /**
-   * Public version of findIntersections.
-   * @param planetModel is the planet model.
-   * @param q is the plane to intersect with.
-   * @param bounds are the bounds to consider to determine legal intersection points.
-   * @return the set of legal intersection points.
-   */
-  public GeoPoint[] findIntersections(final PlanetModel planetModel, final Plane q, final Membership... bounds) {
-    if (isNumericallyIdentical(q)) {
-      return null;
-    }
-    return findIntersections(planetModel, q, bounds, NO_BOUNDS);
-  }
-  
-  /**
-   * Find the intersection points between two planes, given a set of bounds.
-   *
-   * @param planetModel is the planet model to use in finding points.
-   * @param q          is the plane to intersect with.
-   * @param bounds     is the set of bounds.
-   * @param moreBounds is another set of bounds.
-   * @return the intersection point(s) on the unit sphere, if there are any.
-   */
-  protected GeoPoint[] findIntersections(final PlanetModel planetModel, final Plane q, final Membership[] bounds, final Membership[] moreBounds) {
-    //System.err.println("Looking for intersection between plane "+this+" and plane "+q+" within bounds");
-    // Unnormalized, unchecked...
-    final Vector lineVector = new Vector(y * q.z - z * q.y, z * q.x - x * q.z, x * q.y - y * q.x);
-    if (Math.abs(lineVector.x) < MINIMUM_RESOLUTION && Math.abs(lineVector.y) < MINIMUM_RESOLUTION && Math.abs(lineVector.z) < MINIMUM_RESOLUTION) {
-      // Degenerate case: parallel planes
-      //System.err.println(" planes are parallel - no intersection");
-      return NO_POINTS;
-    }
-
-    // The line will have the equation: A t + A0 = x, B t + B0 = y, C t + C0 = z.
-    // We have A, B, and C.  In order to come up with A0, B0, and C0, we need to find a point that is on both planes.
-    // To do this, we find the largest vector value (either x, y, or z), and look for a point that solves both plane equations
-    // simultaneous.  For example, let's say that the vector is (0.5,0.5,1), and the two plane equations are:
-    // 0.7 x + 0.3 y + 0.1 z + 0.0 = 0
-    // and
-    // 0.9 x - 0.1 y + 0.2 z + 4.0 = 0
-    // Then we'd pick z = 0, so the equations to solve for x and y would be:
-    // 0.7 x + 0.3y = 0.0
-    // 0.9 x - 0.1y = -4.0
-    // ... which can readily be solved using standard linear algebra.  Generally:
-    // Q0 x + R0 y = S0
-    // Q1 x + R1 y = S1
-    // ... can be solved by Cramer's rule:
-    // x = det(S0 R0 / S1 R1) / det(Q0 R0 / Q1 R1)
-    // y = det(Q0 S0 / Q1 S1) / det(Q0 R0 / Q1 R1)
-    // ... where det( a b / c d ) = ad - bc, so:
-    // x = (S0 * R1 - R0 * S1) / (Q0 * R1 - R0 * Q1)
-    // y = (Q0 * S1 - S0 * Q1) / (Q0 * R1 - R0 * Q1)
-    double x0;
-    double y0;
-    double z0;
-    // We try to maximize the determinant in the denominator
-    final double denomYZ = this.y * q.z - this.z * q.y;
-    final double denomXZ = this.x * q.z - this.z * q.x;
-    final double denomXY = this.x * q.y - this.y * q.x;
-    if (Math.abs(denomYZ) >= Math.abs(denomXZ) && Math.abs(denomYZ) >= Math.abs(denomXY)) {
-      // X is the biggest, so our point will have x0 = 0.0
-      if (Math.abs(denomYZ) < MINIMUM_RESOLUTION_SQUARED) {
-        //System.err.println(" Denominator is zero: no intersection");
-        return NO_POINTS;
-      }
-      final double denom = 1.0 / denomYZ;
-      x0 = 0.0;
-      y0 = (-this.D * q.z - this.z * -q.D) * denom;
-      z0 = (this.y * -q.D + this.D * q.y) * denom;
-    } else if (Math.abs(denomXZ) >= Math.abs(denomXY) && Math.abs(denomXZ) >= Math.abs(denomYZ)) {
-      // Y is the biggest, so y0 = 0.0
-      if (Math.abs(denomXZ) < MINIMUM_RESOLUTION_SQUARED) {
-        //System.err.println(" Denominator is zero: no intersection");
-        return NO_POINTS;
-      }
-      final double denom = 1.0 / denomXZ;
-      x0 = (-this.D * q.z - this.z * -q.D) * denom;
-      y0 = 0.0;
-      z0 = (this.x * -q.D + this.D * q.x) * denom;
-    } else {
-      // Z is the biggest, so Z0 = 0.0
-      if (Math.abs(denomXY) < MINIMUM_RESOLUTION_SQUARED) {
-        //System.err.println(" Denominator is zero: no intersection");
-        return NO_POINTS;
-      }
-      final double denom = 1.0 / denomXY;
-      x0 = (-this.D * q.y - this.y * -q.D) * denom;
-      y0 = (this.x * -q.D + this.D * q.x) * denom;
-      z0 = 0.0;
-    }
-
-    // Once an intersecting line is determined, the next step is to intersect that line with the ellipsoid, which
-    // will yield zero, one, or two points.
-    // The ellipsoid equation: 1,0 = x^2/a^2 + y^2/b^2 + z^2/c^2
-    // 1.0 = (At+A0)^2/a^2 + (Bt+B0)^2/b^2 + (Ct+C0)^2/c^2
-    // A^2 t^2 / a^2 + 2AA0t / a^2 + A0^2 / a^2 + B^2 t^2 / b^2 + 2BB0t / b^2 + B0^2 / b^2 + C^2 t^2 / c^2 + 2CC0t / c^2 + C0^2 / c^2  - 1,0 = 0.0
-    // [A^2 / a^2 + B^2 / b^2 + C^2 / c^2] t^2 + [2AA0 / a^2 + 2BB0 / b^2 + 2CC0 / c^2] t + [A0^2 / a^2 + B0^2 / b^2 + C0^2 / c^2 - 1,0] = 0.0
-    // Use the quadratic formula to determine t values and candidate point(s)
-    final double A = lineVector.x * lineVector.x * planetModel.inverseAbSquared +
-      lineVector.y * lineVector.y * planetModel.inverseAbSquared +
-      lineVector.z * lineVector.z * planetModel.inverseCSquared;
-    final double B = 2.0 * (lineVector.x * x0 * planetModel.inverseAbSquared + lineVector.y * y0 * planetModel.inverseAbSquared + lineVector.z * z0 * planetModel.inverseCSquared);
-    final double C = x0 * x0 * planetModel.inverseAbSquared + y0 * y0 * planetModel.inverseAbSquared + z0 * z0 * planetModel.inverseCSquared - 1.0;
-
-    final double BsquaredMinus = B * B - 4.0 * A * C;
-    if (Math.abs(BsquaredMinus) < MINIMUM_RESOLUTION_SQUARED) {
-      //System.err.println(" One point of intersection");
-      final double inverse2A = 1.0 / (2.0 * A);
-      // One solution only
-      final double t = -B * inverse2A;
-      GeoPoint point = new GeoPoint(lineVector.x * t + x0, lineVector.y * t + y0, lineVector.z * t + z0);
-      //System.err.println("  point: "+point);
-      //verifyPoint(planetModel, point, q);
-      if (point.isWithin(bounds, moreBounds))
-        return new GeoPoint[]{point};
-      return NO_POINTS;
-    } else if (BsquaredMinus > 0.0) {
-      //System.err.println(" Two points of intersection");
-      final double inverse2A = 1.0 / (2.0 * A);
-      // Two solutions
-      final double sqrtTerm = Math.sqrt(BsquaredMinus);
-      final double t1 = (-B + sqrtTerm) * inverse2A;
-      final double t2 = (-B - sqrtTerm) * inverse2A;
-      GeoPoint point1 = new GeoPoint(lineVector.x * t1 + x0, lineVector.y * t1 + y0, lineVector.z * t1 + z0);
-      GeoPoint point2 = new GeoPoint(lineVector.x * t2 + x0, lineVector.y * t2 + y0, lineVector.z * t2 + z0);
-      //verifyPoint(planetModel, point1, q);
-      //verifyPoint(planetModel, point2, q);
-      //System.err.println("  "+point1+" and "+point2);
-      if (point1.isWithin(bounds, moreBounds)) {
-        if (point2.isWithin(bounds, moreBounds))
-          return new GeoPoint[]{point1, point2};
-        return new GeoPoint[]{point1};
-      }
-      if (point2.isWithin(bounds, moreBounds))
-        return new GeoPoint[]{point2};
-      return NO_POINTS;
-    } else {
-      //System.err.println(" no solutions - no intersection");
-      return NO_POINTS;
-    }
-  }
-
-  /*
-  protected void verifyPoint(final PlanetModel planetModel, final GeoPoint point, final Plane q) {
-    if (!evaluateIsZero(point))
-      throw new RuntimeException("Intersection point not on original plane; point="+point+", plane="+this);
-    if (!q.evaluateIsZero(point))
-      throw new RuntimeException("Intersection point not on intersected plane; point="+point+", plane="+q);
-    if (Math.abs(point.x * point.x * planetModel.inverseASquared + point.y * point.y * planetModel.inverseBSquared + point.z * point.z * planetModel.inverseCSquared - 1.0) >= MINIMUM_RESOLUTION) 
-      throw new RuntimeException("Intersection point not on ellipsoid; point="+point);
-  }
-  */
-
-  /**
-   * Accumulate (x,y,z) bounds information for this plane, intersected with the unit sphere.
-   * Updates min/max information, using max/min points found
-   * within the specified bounds.
-   *
-   * @param planetModel is the planet model to use in determining bounds.
-   * @param boundsInfo is the xyz info to update with additional bounding information.
-   * @param bounds     are the surfaces delineating what's inside the shape.
-   */
-  public void recordBounds(final PlanetModel planetModel, final XYZBounds boundsInfo, final Membership... bounds) {
-    // Basic plan is to do three intersections of the plane and the planet.
-    // For min/max x, we intersect a vertical plane such that y = 0.
-    // For min/max y, we intersect a vertical plane such that x = 0.
-    // For min/max z, we intersect a vertical plane that is chosen to go through the high point of the arc.
-    // For clarity, load local variables with good names
-    final double A = this.x;
-    final double B = this.y;
-    final double C = this.z;
-
-    // Do Z.  This can be done simply because it is symmetrical.
-    if (!boundsInfo.isSmallestMinZ(planetModel) || !boundsInfo.isLargestMaxZ(planetModel)) {
-      //System.err.println("    computing Z bound");
-      // Compute Z bounds for this arc
-      // With ellipsoids, we really have only one viable way to do this computation.
-      // Specifically, we compute an appropriate vertical plane, based on the current plane's x-y orientation, and
-      // then intersect it with this one and with the ellipsoid.  This gives us zero, one, or two points to use
-      // as bounds.
-      // There is one special case: horizontal circles.  These require TWO vertical planes: one for the x, and one for
-      // the y, and we use all four resulting points in the bounds computation.
-      if ((Math.abs(A) >= MINIMUM_RESOLUTION || Math.abs(B) >= MINIMUM_RESOLUTION)) {
-        // NOT a degenerate case
-        //System.err.println("    not degenerate");
-        final Plane normalizedZPlane = constructNormalizedZPlane(A,B);
-        final GeoPoint[] points = findIntersections(planetModel, normalizedZPlane, bounds, NO_BOUNDS);
-        for (final GeoPoint point : points) {
-          assert planetModel.pointOnSurface(point);
-          //System.err.println("      Point = "+point+"; this.evaluate(point)="+this.evaluate(point)+"; normalizedZPlane.evaluate(point)="+normalizedZPlane.evaluate(point));
-          addPoint(boundsInfo, bounds, point);
-        }
-      } else {
-        // Since a==b==0, any plane including the Z axis suffices.
-        //System.err.println("      Perpendicular to z");
-        final GeoPoint[] points = findIntersections(planetModel, normalYPlane, NO_BOUNDS, NO_BOUNDS);
-        boundsInfo.addZValue(points[0]);
-      }
-    }
-
-    // First, compute common subexpressions
-    final double k = 1.0 / ((x*x + y*y)*planetModel.ab*planetModel.ab + z*z*planetModel.c*planetModel.c);
-    final double abSquared = planetModel.ab * planetModel.ab;
-    final double cSquared = planetModel.c * planetModel.c;
-    final double ASquared = A * A;
-    final double BSquared = B * B;
-    final double CSquared = C * C;
-    
-    final double r = 2.0*D*k;
-    final double rSquared = r * r;
-    
-    if (!boundsInfo.isSmallestMinX(planetModel) || !boundsInfo.isLargestMaxX(planetModel)) {
-      // For min/max x, we need to use lagrange multipliers.
-      //
-      // For this, we need grad(F(x,y,z)) = (dF/dx, dF/dy, dF/dz).
-      //
-      // Minimize and maximize f(x,y,z) = x, with respect to g(x,y,z) = Ax + By + Cz - D and h(x,y,z) = x^2/ab^2 + y^2/ab^2 + z^2/c^2 - 1
-      //
-      // grad(f(x,y,z)) = (1,0,0)
-      // grad(g(x,y,z)) = (A,B,C)
-      // grad(h(x,y,z)) = (2x/ab^2,2y/ab^2,2z/c^2)
-      //
-      // Equations we need to simultaneously solve:
-      // 
-      // grad(f(x,y,z)) = l * grad(g(x,y,z)) + m * grad(h(x,y,z))
-      // g(x,y,z) = 0
-      // h(x,y,z) = 0
-      // 
-      // Equations:
-      // 1 = l*A + m*2x/ab^2
-      // 0 = l*B + m*2y/ab^2
-      // 0 = l*C + m*2z/c^2
-      // Ax + By + Cz + D = 0
-      // x^2/ab^2 + y^2/ab^2 + z^2/c^2 - 1 = 0
-      // 
-      // Solve for x,y,z in terms of (l, m):
-      // 
-      // x = ((1 - l*A) * ab^2 ) / (2 * m)
-      // y = (-l*B * ab^2) / ( 2 * m)
-      // z = (-l*C * c^2)/ (2 * m)
-      // 
-      // Two equations, two unknowns:
-      // 
-      // A * (((1 - l*A) * ab^2 ) / (2 * m)) + B * ((-l*B * ab^2) / ( 2 * m)) + C * ((-l*C * c^2)/ (2 * m)) + D = 0
-      // 
-      // and
-      // 
-      // (((1 - l*A) * ab^2 ) / (2 * m))^2/ab^2 + ((-l*B * ab^2) / ( 2 * m))^2/ab^2 + ((-l*C * c^2)/ (2 * m))^2/c^2 - 1 = 0
-      // 
-      // Simple: solve for l and m, then find x from it.
-      // 
-      // (a) Use first equation to find l in terms of m.
-      // 
-      // A * (((1 - l*A) * ab^2 ) / (2 * m)) + B * ((-l*B * ab^2) / ( 2 * m)) + C * ((-l*C * c^2)/ (2 * m)) + D = 0
-      // A * ((1 - l*A) * ab^2 ) + B * (-l*B * ab^2) + C * (-l*C * c^2) + D * 2 * m = 0
-      // A * ab^2 - l*A^2* ab^2 - B^2 * l * ab^2 - C^2 * l * c^2 + D * 2 * m = 0
-      // - l *(A^2* ab^2 + B^2 * ab^2 + C^2 * c^2) + (A * ab^2 + D * 2 * m) = 0
-      // l = (A * ab^2 + D * 2 * m) / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
-      // l = A * ab^2 / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2) + m * 2 * D / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
-      // 
-      // For convenience:
-      // 
-      // k = 1.0 / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
-      // 
-      // Then:
-      // 
-      // l = A * ab^2 * k + m * 2 * D * k
-      // l = k * (A*ab^2 + m*2*D)
-      //
-      // For further convenience:
-      //
-      // q = A*ab^2*k
-      // r = 2*D*k
-      //
-      // l = (r*m + q)
-      // l^2 = (r^2 * m^2 + 2*r*m*q + q^2)
-      // 
-      // (b) Simplify the second equation before substitution
-      // 
-      // (((1 - l*A) * ab^2 ) / (2 * m))^2/ab^2 + ((-l*B * ab^2) / ( 2 * m))^2/ab^2 + ((-l*C * c^2)/ (2 * m))^2/c^2 - 1 = 0
-      // ((1 - l*A) * ab^2 )^2/ab^2 + (-l*B * ab^2)^2/ab^2 + (-l*C * c^2)^2/c^2 = 4 * m^2
-      // (1 - l*A)^2 * ab^2 + (-l*B)^2 * ab^2 + (-l*C)^2 * c^2 = 4 * m^2
-      // (1 - 2*l*A + l^2*A^2) * ab^2 + l^2*B^2 * ab^2 + l^2*C^2 * c^2 = 4 * m^2
-      // ab^2 - 2*A*ab^2*l + A^2*ab^2*l^2 + B^2*ab^2*l^2 + C^2*c^2*l^2 - 4*m^2 = 0
-      // 
-      // (c) Substitute for l, l^2
-      //
-      // ab^2 - 2*A*ab^2*(r*m + q) + A^2*ab^2*(r^2 * m^2 + 2*r*m*q + q^2) + B^2*ab^2*(r^2 * m^2 + 2*r*m*q + q^2) + C^2*c^2*(r^2 * m^2 + 2*r*m*q + q^2) - 4*m^2 = 0
-      // ab^2 - 2*A*ab^2*r*m - 2*A*ab^2*q + A^2*ab^2*r^2*m^2 + 2*A^2*ab^2*r*q*m +
-      //        A^2*ab^2*q^2 + B^2*ab^2*r^2*m^2 + 2*B^2*ab^2*r*q*m + B^2*ab^2*q^2 + C^2*c^2*r^2*m^2 + 2*C^2*c^2*r*q*m + C^2*c^2*q^2 - 4*m^2 = 0
-      //
-      // (d) Group
-      //
-      // m^2 * [A^2*ab^2*r^2 + B^2*ab^2*r^2 + C^2*c^2*r^2 - 4] +
-      // m * [- 2*A*ab^2*r + 2*A^2*ab^2*r*q + 2*B^2*ab^2*r*q + 2*C^2*c^2*r*q] +
-      // [ab^2 - 2*A*ab^2*q + A^2*ab^2*q^2 + B^2*ab^2*q^2 + C^2*c^2*q^2]  =  0
-      
-      //System.err.println("    computing X bound");
-      
-      // Useful subexpressions for this bound
-      final double q = A*abSquared*k;
-      final double qSquared = q * q;
-
-      // Quadratic equation
-      final double a = ASquared*abSquared*rSquared + BSquared*abSquared*rSquared + CSquared*cSquared*rSquared - 4.0;
-      final double b = - 2.0*A*abSquared*r + 2.0*ASquared*abSquared*r*q + 2.0*BSquared*abSquared*r*q + 2.0*CSquared*cSquared*r*q;
-      final double c = abSquared - 2.0*A*abSquared*q + ASquared*abSquared*qSquared + BSquared*abSquared*qSquared + CSquared*cSquared*qSquared;
-      
-      if (Math.abs(a) >= MINIMUM_RESOLUTION_SQUARED) {
-        final double sqrtTerm = b*b - 4.0*a*c;
-        if (Math.abs(sqrtTerm) < MINIMUM_RESOLUTION_SQUARED) {
-          // One solution
-          final double m = -b / (2.0 * a);
-          final double l = r * m + q;
-          // x = ((1 - l*A) * ab^2 ) / (2 * m)
-          // y = (-l*B * ab^2) / ( 2 * m)
-          // z = (-l*C * c^2)/ (2 * m)
-          final double denom0 = 0.5 / m;
-          final GeoPoint thePoint = new GeoPoint((1.0-l*A) * abSquared * denom0, -l*B * abSquared * denom0, -l*C * cSquared * denom0);
-          //Math is not quite accurate enough for this
-          //assert planetModel.pointOnSurface(thePoint): "Point: "+thePoint+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
-          //  (thePoint.x*thePoint.x*planetModel.inverseAb*planetModel.inverseAb + thePoint.y*thePoint.y*planetModel.inverseAb*planetModel.inverseAb + thePoint.z*thePoint.z*planetModel.inverseC*planetModel.inverseC);
-          //assert evaluateIsZero(thePoint): "Evaluation of point: "+evaluate(thePoint);
-          addPoint(boundsInfo, bounds, thePoint);
-        } else if (sqrtTerm > 0.0) {
-          // Two solutions
-          final double sqrtResult = Math.sqrt(sqrtTerm);
-          final double commonDenom = 0.5/a;
-          final double m1 = (-b + sqrtResult) * commonDenom;
-          assert Math.abs(a * m1 * m1 + b * m1 + c) < MINIMUM_RESOLUTION;
-          final double m2 = (-b - sqrtResult) * commonDenom;
-          assert Math.abs(a * m2 * m2 + b * m2 + c) < MINIMUM_RESOLUTION;
-          final double l1 = r * m1 + q;
-          final double l2 = r * m2 + q;
-          // x = ((1 - l*A) * ab^2 ) / (2 * m)
-          // y = (-l*B * ab^2) / ( 2 * m)
-          // z = (-l*C * c^2)/ (2 * m)
-          final double denom1 = 0.5 / m1;
-          final double denom2 = 0.5 / m2;
-          final GeoPoint thePoint1 = new GeoPoint((1.0-l1*A) * abSquared * denom1, -l1*B * abSquared * denom1, -l1*C * cSquared * denom1);
-          final GeoPoint thePoint2 = new GeoPoint((1.0-l2*A) * abSquared * denom2, -l2*B * abSquared * denom2, -l2*C * cSquared * denom2);
-          //Math is not quite accurate enough for this
-          //assert planetModel.pointOnSurface(thePoint1): "Point1: "+thePoint1+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
-          //  (thePoint1.x*thePoint1.x*planetModel.inverseAb*planetModel.inverseAb + thePoint1.y*thePoint1.y*planetModel.inverseAb*planetModel.inverseAb + thePoint1.z*thePoint1.z*planetModel.inverseC*planetModel.inverseC);
-          //assert planetModel.pointOnSurface(thePoint2): "Point1: "+thePoint2+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
-          //  (thePoint2.x*thePoint2.x*planetModel.inverseAb*planetModel.inverseAb + thePoint2.y*thePoint2.y*planetModel.inverseAb*planetModel.inverseAb + thePoint2.z*thePoint2.z*planetModel.inverseC*planetModel.inverseC);
-          //assert evaluateIsZero(thePoint1): "Evaluation of point1: "+evaluate(thePoint1);
-          //assert evaluateIsZero(thePoint2): "Evaluation of point2: "+evaluate(thePoint2);
-          addPoint(boundsInfo, bounds, thePoint1);
-          addPoint(boundsInfo, bounds, thePoint2);
-        } else {
-          // No solutions
-        }
-      } else if (Math.abs(b) > MINIMUM_RESOLUTION_SQUARED) {
-        //System.err.println("Not x quadratic");
-        // a = 0, so m = - c / b
-        final double m = -c / b;
-        final double l = r * m + q;
-        // x = ((1 - l*A) * ab^2 ) / (2 * m)
-        // y = (-l*B * ab^2) / ( 2 * m)
-        // z = (-l*C * c^2)/ (2 * m)
-        final double denom0 = 0.5 / m;
-        final GeoPoint thePoint = new GeoPoint((1.0-l*A) * abSquared * denom0, -l*B * abSquared * denom0, -l*C * cSquared * denom0);
-        //Math is not quite accurate enough for this
-        //assert planetModel.pointOnSurface(thePoint): "Point: "+thePoint+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
-        //  (thePoint.x*thePoint.x*planetModel.inverseAb*planetModel.inverseAb + thePoint.y*thePoint.y*planetModel.inverseAb*planetModel.inverseAb + thePoint.z*thePoint.z*planetModel.inverseC*planetModel.inverseC);
-        //assert evaluateIsZero(thePoint): "Evaluation of point: "+evaluate(thePoint);
-        addPoint(boundsInfo, bounds, thePoint);
-      } else {
-        // Something went very wrong; a = b = 0
-      }
-    }
-    
-    // Do Y
-    if (!boundsInfo.isSmallestMinY(planetModel) || !boundsInfo.isLargestMaxY(planetModel)) {
-      // For min/max x, we need to use lagrange multipliers.
-      //
-      // For this, we need grad(F(x,y,z)) = (dF/dx, dF/dy, dF/dz).
-      //
-      // Minimize and maximize f(x,y,z) = y, with respect to g(x,y,z) = Ax + By + Cz - D and h(x,y,z) = x^2/ab^2 + y^2/ab^2 + z^2/c^2 - 1
-      //
-      // grad(f(x,y,z)) = (0,1,0)
-      // grad(g(x,y,z)) = (A,B,C)
-      // grad(h(x,y,z)) = (2x/ab^2,2y/ab^2,2z/c^2)
-      //
-      // Equations we need to simultaneously solve:
-      // 
-      // grad(f(x,y,z)) = l * grad(g(x,y,z)) + m * grad(h(x,y,z))
-      // g(x,y,z) = 0
-      // h(x,y,z) = 0
-      // 
-      // Equations:
-      // 0 = l*A + m*2x/ab^2
-      // 1 = l*B + m*2y/ab^2
-      // 0 = l*C + m*2z/c^2
-      // Ax + By + Cz + D = 0
-      // x^2/ab^2 + y^2/ab^2 + z^2/c^2 - 1 = 0
-      // 
-      // Solve for x,y,z in terms of (l, m):
-      // 
-      // x = (-l*A * ab^2 ) / (2 * m)
-      // y = ((1 - l*B) * ab^2) / ( 2 * m)
-      // z = (-l*C * c^2)/ (2 * m)
-      // 
-      // Two equations, two unknowns:
-      // 
-      // A * ((-l*A * ab^2 ) / (2 * m)) + B * (((1 - l*B) * ab^2) / ( 2 * m)) + C * ((-l*C * c^2)/ (2 * m)) + D = 0
-      // 
-      // and
-      // 
-      // ((-l*A * ab^2 ) / (2 * m))^2/ab^2 + (((1 - l*B) * ab^2) / ( 2 * m))^2/ab^2 + ((-l*C * c^2)/ (2 * m))^2/c^2 - 1 = 0
-      // 
-      // Simple: solve for l and m, then find y from it.
-      // 
-      // (a) Use first equation to find l in terms of m.
-      // 
-      // A * ((-l*A * ab^2 ) / (2 * m)) + B * (((1 - l*B) * ab^2) / ( 2 * m)) + C * ((-l*C * c^2)/ (2 * m)) + D = 0
-      // A * (-l*A * ab^2 ) + B * ((1-l*B) * ab^2) + C * (-l*C * c^2) + D * 2 * m = 0
-      // -A^2*l*ab^2 + B*ab^2 - l*B^2*ab^2 - C^2*l*c^2 + D*2*m = 0
-      // - l *(A^2* ab^2 + B^2 * ab^2 + C^2 * c^2) + (B * ab^2 + D * 2 * m) = 0
-      // l = (B * ab^2 + D * 2 * m) / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
-      // l = B * ab^2 / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2) + m * 2 * D / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
-      // 
-      // For convenience:
-      // 
-      // k = 1.0 / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
-      // 
-      // Then:
-      // 
-      // l = B * ab^2 * k + m * 2 * D * k
-      // l = k * (B*ab^2 + m*2*D)
-      //
-      // For further convenience:
-      //
-      // q = B*ab^2*k
-      // r = 2*D*k
-      //
-      // l = (r*m + q)
-      // l^2 = (r^2 * m^2 + 2*r*m*q + q^2)
-      // 
-      // (b) Simplify the second equation before substitution
-      // 
-      // ((-l*A * ab^2 ) / (2 * m))^2/ab^2 + (((1 - l*B) * ab^2) / ( 2 * m))^2/ab^2 + ((-l*C * c^2)/ (2 * m))^2/c^2 - 1 = 0
-      // (-l*A * ab^2 )^2/ab^2 + ((1 - l*B) * ab^2)^2/ab^2 + (-l*C * c^2)^2/c^2 = 4 * m^2
-      // (-l*A)^2 * ab^2 + (1 - l*B)^2 * ab^2 + (-l*C)^2 * c^2 = 4 * m^2
-      // l^2*A^2 * ab^2 + (1 - 2*l*B + l^2*B^2) * ab^2 + l^2*C^2 * c^2 = 4 * m^2
-      // A^2*ab^2*l^2 + ab^2 - 2*B*ab^2*l + B^2*ab^2*l^2 + C^2*c^2*l^2 - 4*m^2 = 0
-      // 
-      // (c) Substitute for l, l^2
-      //
-      // A^2*ab^2*(r^2 * m^2 + 2*r*m*q + q^2) + ab^2 - 2*B*ab^2*(r*m + q) + B^2*ab^2*(r^2 * m^2 + 2*r*m*q + q^2) + C^2*c^2*(r^2 * m^2 + 2*r*m*q + q^2) - 4*m^2 = 0
-      // A^2*ab^2*r^2*m^2 + 2*A^2*ab^2*r*q*m + A^2*ab^2*q^2 + ab^2 - 2*B*ab^2*r*m - 2*B*ab^2*q + B^2*ab^2*r^2*m^2 +
-      //    2*B^2*ab^2*r*q*m + B^2*ab^2*q^2 + C^2*c^2*r^2*m^2 + 2*C^2*c^2*r*q*m + C^2*c^2*q^2 - 4*m^2 = 0
-      //
-      // (d) Group
-      //
-      // m^2 * [A^2*ab^2*r^2 + B^2*ab^2*r^2 + C^2*c^2*r^2 - 4] +
-      // m * [2*A^2*ab^2*r*q - 2*B*ab^2*r + 2*B^2*ab^2*r*q + 2*C^2*c^2*r*q] +
-      // [A^2*ab^2*q^2 + ab^2 - 2*B*ab^2*q + B^2*ab^2*q^2 + C^2*c^2*q^2]  =  0
-
-      //System.err.println("    computing Y bound");
-      
-      // Useful subexpressions for this bound
-      final double q = B*abSquared*k;
-      final double qSquared = q * q;
-
-      // Quadratic equation
-      final double a = ASquared*abSquared*rSquared + BSquared*abSquared*rSquared + CSquared*cSquared*rSquared - 4.0;
-      final double b = 2.0*ASquared*abSquared*r*q - 2.0*B*abSquared*r + 2.0*BSquared*abSquared*r*q + 2.0*CSquared*cSquared*r*q;
-      final double c = ASquared*abSquared*qSquared + abSquared - 2.0*B*abSquared*q + BSquared*abSquared*qSquared + CSquared*cSquared*qSquared;
-
-      if (Math.abs(a) >= MINIMUM_RESOLUTION_SQUARED) {
-        final double sqrtTerm = b*b - 4.0*a*c;
-        if (Math.abs(sqrtTerm) < MINIMUM_RESOLUTION_SQUARED) {
-          // One solution
-          final double m = -b / (2.0 * a);
-          final double l = r * m + q;
-          // x = (-l*A * ab^2 ) / (2 * m)
-          // y = ((1.0-l*B) * ab^2) / ( 2 * m)
-          // z = (-l*C * c^2)/ (2 * m)
-          final double denom0 = 0.5 / m;
-          final GeoPoint thePoint = new GeoPoint(-l*A * abSquared * denom0, (1.0-l*B) * abSquared * denom0, -l*C * cSquared * denom0);
-          //Math is not quite accurate enough for this
-          //assert planetModel.pointOnSurface(thePoint): "Point: "+thePoint+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
-          //  (thePoint1.x*thePoint.x*planetModel.inverseAb*planetModel.inverseAb + thePoint.y*thePoint.y*planetModel.inverseAb*planetModel.inverseAb + thePoint.z*thePoint.z*planetModel.inverseC*planetModel.inverseC);
-          //assert evaluateIsZero(thePoint): "Evaluation of point: "+evaluate(thePoint);
-          addPoint(boundsInfo, bounds, thePoint);
-        } else if (sqrtTerm > 0.0) {
-          // Two solutions
-          final double sqrtResult = Math.sqrt(sqrtTerm);
-          final double commonDenom = 0.5/a;
-          final double m1 = (-b + sqrtResult) * commonDenom;
-          assert Math.abs(a * m1 * m1 + b * m1 + c) < MINIMUM_RESOLUTION;
-          final double m2 = (-b - sqrtResult) * commonDenom;
-          assert Math.abs(a * m2 * m2 + b * m2 + c) < MINIMUM_RESOLUTION;
-          final double l1 = r * m1 + q;
-          final double l2 = r * m2 + q;
-          // x = (-l*A * ab^2 ) / (2 * m)
-          // y = ((1.0-l*B) * ab^2) / ( 2 * m)
-          // z = (-l*C * c^2)/ (2 * m)
-          final double denom1 = 0.5 / m1;
-          final double denom2 = 0.5 / m2;
-          final GeoPoint thePoint1 = new GeoPoint(-l1*A * abSquared * denom1, (1.0-l1*B) * abSquared * denom1, -l1*C * cSquared * denom1);
-          final GeoPoint thePoint2 = new GeoPoint(-l2*A * abSquared * denom2, (1.0-l2*B) * abSquared * denom2, -l2*C * cSquared * denom2);
-          //Math is not quite accurate enough for this
-          //assert planetModel.pointOnSurface(thePoint1): "Point1: "+thePoint1+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
-          //  (thePoint1.x*thePoint1.x*planetModel.inverseAb*planetModel.inverseAb + thePoint1.y*thePoint1.y*planetModel.inverseAb*planetModel.inverseAb + thePoint1.z*thePoint1.z*planetModel.inverseC*planetModel.inverseC);
-          //assert planetModel.pointOnSurface(thePoint2): "Point2: "+thePoint2+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
-          //  (thePoint2.x*thePoint2.x*planetModel.inverseAb*planetModel.inverseAb + thePoint2.y*thePoint2.y*planetModel.inverseAb*planetModel.inverseAb + thePoint2.z*thePoint2.z*planetModel.inverseC*planetModel.inverseC);
-          //assert evaluateIsZero(thePoint1): "Evaluation of point1: "+evaluate(thePoint1);
-          //assert evaluateIsZero(thePoint2): "Evaluation of point2: "+evaluate(thePoint2);
-          addPoint(boundsInfo, bounds, thePoint1);
-          addPoint(boundsInfo, bounds, thePoint2);
-        } else {
-          // No solutions
-        }
-      } else if (Math.abs(b) > MINIMUM_RESOLUTION_SQUARED) {
-        // a = 0, so m = - c / b
-        final double m = -c / b;
-        final double l = r * m + q;
-        // x = ( -l*A * ab^2 ) / (2 * m)
-        // y = ((1-l*B) * ab^2) / ( 2 * m)
-        // z = (-l*C * c^2)/ (2 * m)
-        final double denom0 = 0.5 / m;
-        final GeoPoint thePoint = new GeoPoint(-l*A * abSquared * denom0, (1.0-l*B) * abSquared * denom0, -l*C * cSquared * denom0);
-        //Math is not quite accurate enough for this
-        //assert planetModel.pointOnSurface(thePoint): "Point: "+thePoint+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
-        //  (thePoint.x*thePoint.x*planetModel.inverseAb*planetModel.inverseAb + thePoint.y*thePoint.y*planetModel.inverseAb*planetModel.inverseAb + thePoint.z*thePoint.z*planetModel.inverseC*planetModel.inverseC);
-        //assert evaluateIsZero(thePoint): "Evaluation of point: "+evaluate(thePoint);
-        addPoint(boundsInfo, bounds, thePoint);
-      } else {
-        // Something went very wrong; a = b = 0
-      }
-    }
-  }
-  
-  /**
-   * Accumulate bounds information for this plane, intersected with the unit sphere.
-   * Updates both latitude and longitude information, using max/min points found
-   * within the specified bounds.
-   *
-   * @param planetModel is the planet model to use in determining bounds.
-   * @param boundsInfo is the lat/lon info to update with additional bounding information.
-   * @param bounds     are the surfaces delineating what's inside the shape.
-   */
-  public void recordBounds(final PlanetModel planetModel, final LatLonBounds boundsInfo, final Membership... bounds) {
-    // For clarity, load local variables with good names
-    final double A = this.x;
-    final double B = this.y;
-    final double C = this.z;
-
-    // Now compute latitude min/max points
-    if (!boundsInfo.checkNoTopLatitudeBound() || !boundsInfo.checkNoBottomLatitudeBound()) {
-      //System.err.println("Looking at latitude for plane "+this);
-      // With ellipsoids, we really have only one viable way to do this computation.
-      // Specifically, we compute an appropriate vertical plane, based on the current plane's x-y orientation, and
-      // then intersect it with this one and with the ellipsoid.  This gives us zero, one, or two points to use
-      // as bounds.
-      // There is one special case: horizontal circles.  These require TWO vertical planes: one for the x, and one for
-      // the y, and we use all four resulting points in the bounds computation.
-      if ((Math.abs(A) >= MINIMUM_RESOLUTION || Math.abs(B) >= MINIMUM_RESOLUTION)) {
-        // NOT a horizontal circle!
-        //System.err.println(" Not a horizontal circle");
-        final Plane verticalPlane = constructNormalizedZPlane(A,B);
-        final GeoPoint[] points = findIntersections(planetModel, verticalPlane, bounds, NO_BOUNDS);
-        for (final GeoPoint point : points) {
-          addPoint(boundsInfo, bounds, point);
-        }
-      } else {
-        // Horizontal circle.  Since a==b, any vertical plane suffices.
-        final GeoPoint[] points = findIntersections(planetModel, normalXPlane, NO_BOUNDS, NO_BOUNDS);
-        boundsInfo.addZValue(points[0]);
-      }
-      //System.err.println("Done latitude bounds");
-    }
-
-    // First, figure out our longitude bounds, unless we no longer need to consider that
-    if (!boundsInfo.checkNoLongitudeBound()) {
-      //System.err.println("Computing longitude bounds for "+this);
-      //System.out.println("A = "+A+" B = "+B+" C = "+C+" D = "+D);
-      // Compute longitude bounds
-
-      double a;
-      double b;
-      double c;
-
-      if (Math.abs(C) < MINIMUM_RESOLUTION) {
-        // Degenerate; the equation describes a line
-        //System.out.println("It's a zero-width ellipse");
-        // Ax + By + D = 0
-        if (Math.abs(D) >= MINIMUM_RESOLUTION) {
-          if (Math.abs(A) > Math.abs(B)) {
-            // Use equation suitable for A != 0
-            // We need to find the endpoints of the zero-width ellipse.
-            // Geometrically, we have a line segment in x-y space.  We need to locate the endpoints
-            // of that line.  But luckily, we know some things: specifically, since it is a
-            // degenerate situation in projection, the C value had to have been 0.  That
-            // means that our line's endpoints will coincide with the projected ellipse.  All we
-            // need to do then is to find the intersection of the projected ellipse and the line
-            // equation:
-            //
-            // A x + B y + D = 0
-            //
-            // Since A != 0:
-            // x = (-By - D)/A
-            //
-            // The projected ellipse:
-            // x^2/a^2 + y^2/b^2 - 1 = 0
-            // Substitute:
-            // [(-By-D)/A]^2/a^2 + y^2/b^2 -1 = 0
-            // Multiply through by A^2:
-            // [-By - D]^2/a^2 + A^2*y^2/b^2 - A^2 = 0
-            // Multiply out:
-            // B^2*y^2/a^2 + 2BDy/a^2 + D^2/a^2 + A^2*y^2/b^2 - A^2 = 0
-            // Group:
-            // y^2 * [B^2/a^2 + A^2/b^2] + y [2BD/a^2] + [D^2/a^2-A^2] = 0
-
-            a = B * B * planetModel.inverseAbSquared + A * A * planetModel.inverseAbSquared;
-            b = 2.0 * B * D * planetModel.inverseAbSquared;
-            c = D * D * planetModel.inverseAbSquared - A * A;
-
-            double sqrtClause = b * b - 4.0 * a * c;
-
-            if (Math.abs(sqrtClause) < MINIMUM_RESOLUTION_SQUARED) {
-              double y0 = -b / (2.0 * a);
-              double x0 = (-D - B * y0) / A;
-              double z0 = 0.0;
-              addPoint(boundsInfo, bounds, new GeoPoint(x0, y0, z0));
-            } else if (sqrtClause > 0.0) {
-              double sqrtResult = Math.sqrt(sqrtClause);
-              double denom = 1.0 / (2.0 * a);
-              double Hdenom = 1.0 / A;
-
-              double y0a = (-b + sqrtResult) * denom;
-              double y0b = (-b - sqrtResult) * denom;
-
-              double x0a = (-D - B * y0a) * Hdenom;
-              double x0b = (-D - B * y0b) * Hdenom;
-
-              double z0a = 0.0;
-              double z0b = 0.0;
-
-              addPoint(boundsInfo, bounds, new GeoPoint(x0a, y0a, z0a));
-              addPoint(boundsInfo, bounds, new GeoPoint(x0b, y0b, z0b));
-            }
-
-          } else {
-            // Use equation suitable for B != 0
-            // Since I != 0, we rewrite:
-            // y = (-Ax - D)/B
-            a = B * B * planetModel.inverseAbSquared + A * A * planetModel.inverseAbSquared;
-            b = 2.0 * A * D * planetModel.inverseAbSquared;
-            c = D * D * planetModel.inverseAbSquared - B * B;
-
-            double sqrtClause = b * b - 4.0 * a * c;
-
-            if (Math.abs(sqrtClause) < MINIMUM_RESOLUTION_SQUARED) {
-              double x0 = -b / (2.0 * a);
-              double y0 = (-D - A * x0) / B;
-              double z0 = 0.0;
-              addPoint(boundsInfo, bounds, new GeoPoint(x0, y0, z0));
-            } else if (sqrtClause > 0.0) {
-              double sqrtResult = Math.sqrt(sqrtClause);
-              double denom = 1.0 / (2.0 * a);
-              double Idenom = 1.0 / B;
-
-              double x0a = (-b + sqrtResult) * denom;
-              double x0b = (-b - sqrtResult) * denom;
-              double y0a = (-D - A * x0a) * Idenom;
-              double y0b = (-D - A * x0b) * Idenom;
-              double z0a = 0.0;
-              double z0b = 0.0;
-
-              addPoint(boundsInfo, bounds, new GeoPoint(x0a, y0a, z0a));
-              addPoint(boundsInfo, bounds, new GeoPoint(x0b, y0b, z0b));
-            }
-          }
-        }
-
-      } else {
-        //System.err.println("General longitude bounds...");
-
-        // NOTE WELL: The x,y,z values generated here are NOT on the unit sphere.
-        // They are for lat/lon calculation purposes only.  x-y is meant to be used for longitude determination,
-        // and z for latitude, and that's all the values are good for.
-
-        // (1) Intersect the plane and the ellipsoid, and project the results into the x-y plane:
-        // From plane:
-        // z = (-Ax - By - D) / C
-        // From ellipsoid:
-        // x^2/a^2 + y^2/b^2 + [(-Ax - By - D) / C]^2/c^2 = 1
-        // Simplify/expand:
-        // C^2*x^2/a^2 + C^2*y^2/b^2 + (-Ax - By - D)^2/c^2 = C^2
-        //
-        // x^2 * C^2/a^2 + y^2 * C^2/b^2 + x^2 * A^2/c^2 + ABxy/c^2 + ADx/c^2 + ABxy/c^2 + y^2 * B^2/c^2 + BDy/c^2 + ADx/c^2 + BDy/c^2 + D^2/c^2 = C^2
-        // Group:
-        // [A^2/c^2 + C^2/a^2] x^2 + [B^2/c^2 + C^2/b^2] y^2 + [2AB/c^2]xy + [2AD/c^2]x + [2BD/c^2]y + [D^2/c^2-C^2] = 0
-        // For convenience, introduce post-projection coefficient variables to make life easier.
-        // E x^2 + F y^2 + G xy + H x + I y + J = 0
-        double E = A * A * planetModel.inverseCSquared + C * C * planetModel.inverseAbSquared;
-        double F = B * B * planetModel.inverseCSquared + C * C * planetModel.inverseAbSquared;
-        double G = 2.0 * A * B * planetModel.inverseCSquared;
-        double H = 2.0 * A * D * planetModel.inverseCSquared;
-        double I = 2.0 * B * D * planetModel.inverseCSquared;
-        double J = D * D * planetModel.inverseCSquared - C * C;
-
-        //System.err.println("E = " + E + " F = " + F + " G = " + G + " H = "+ H + " I = " + I + " J = " + J);
-
-        // Check if the origin is within, by substituting x = 0, y = 0 and seeing if less than zero
-        if (Math.abs(J) >= MINIMUM_RESOLUTION && J > 0.0) {
-          // The derivative of the curve above is:
-          // 2Exdx + 2Fydy + G(xdy+ydx) + Hdx + Idy = 0
-          // (2Ex + Gy + H)dx + (2Fy + Gx + I)dy = 0
-          // dy/dx = - (2Ex + Gy + H) / (2Fy + Gx + I)
-          //
-          // The equation of a line going through the origin with the slope dy/dx is:
-          // y = dy/dx x
-          // y = - (2Ex + Gy + H) / (2Fy + Gx + I)  x
-          // Rearrange:
-          // (2Fy + Gx + I) y + (2Ex + Gy + H) x = 0
-          // 2Fy^2 + Gxy + Iy + 2Ex^2 + Gxy + Hx = 0
-          // 2Ex^2 + 2Fy^2 + 2Gxy + Hx + Iy = 0
-          //
-          // Multiply the original equation by 2:
-          // 2E x^2 + 2F y^2 + 2G xy + 2H x + 2I y + 2J = 0
-          // Subtract one from the other, to remove the high-order terms:
-          // Hx + Iy + 2J = 0
-          // Now, we can substitute either x = or y = into the derivative equation, or into the original equation.
-          // But we will need to base this on which coefficient is non-zero
-
-          if (Math.abs(H) > Math.abs(I)) {
-            //System.err.println(" Using the y quadratic");
-            // x = (-2J - Iy)/H
-
-            // Plug into the original equation:
-            // E [(-2J - Iy)/H]^2 + F y^2 + G [(-2J - Iy)/H]y + H [(-2J - Iy)/H] + I y + J = 0
-            // E [(-2J - Iy)/H]^2 + F y^2 + G [(-2J - Iy)/H]y - J = 0
-            // Same equation as derivative equation, except for a factor of 2!  So it doesn't matter which we pick.
-
-            // Plug into derivative equation:
-            // 2E[(-2J - Iy)/H]^2 + 2Fy^2 + 2G[(-2J - Iy)/H]y + H[(-2J - Iy)/H] + Iy = 0
-            // 2E[(-2J - Iy)/H]^2 + 2Fy^2 + 2G[(-2J - Iy)/H]y - 2J = 0
-            // E[(-2J - Iy)/H]^2 + Fy^2 + G[(-2J - Iy)/H]y - J = 0
-
-            // Multiply by H^2 to make manipulation easier
-            // E[(-2J - Iy)]^2 + F*H^2*y^2 + GH[(-2J - Iy)]y - J*H^2 = 0
-            // Do the square
-            // E[4J^2 + 4IJy + I^2*y^2] + F*H^2*y^2 + GH(-2Jy - I*y^2) - J*H^2 = 0
-
-            // Multiply it out
-            // 4E*J^2 + 4EIJy + E*I^2*y^2 + H^2*Fy^2 - 2GHJy - GH*I*y^2 - J*H^2 = 0
-            // Group:
-            // y^2 [E*I^2 - GH*I + F*H^2] + y [4EIJ - 2GHJ] + [4E*J^2 - J*H^2] = 0
-
-            a = E * I * I - G * H * I + F * H * H;
-            b = 4.0 * E * I * J - 2.0 * G * H * J;
-            c = 4.0 * E * J * J - J * H * H;
-
-            //System.out.println("a="+a+" b="+b+" c="+c);
-            double sqrtClause = b * b - 4.0 * a * c;
-            //System.out.println("sqrtClause="+sqrtClause);
-
-            if (Math.abs(sqrtClause) < MINIMUM_RESOLUTION_CUBED) {
-              //System.err.println(" One solution");
-              double y0 = -b / (2.0 * a);
-              double x0 = (-2.0 * J - I * y0) / H;
-              double z0 = (-A * x0 - B * y0 - D) / C;
-
-              addPoint(boundsInfo, bounds, new GeoPoint(x0, y0, z0));
-            } else if (sqrtClause > 0.0) {
-              //System.err.println(" Two solutions");
-              double sqrtResult = Math.sqrt(sqrtClause);
-              double denom = 1.0 / (2.0 * a);
-              double Hdenom = 1.0 / H;
-              double Cdenom = 1.0 / C;
-
-              double y0a = (-b + sqrtResult) * denom;
-              double y0b = (-b - sqrtResult) * denom;
-              double x0a = (-2.0 * J - I * y0a) * Hdenom;
-              double x0b = (-2.0 * J - I * y0b) * Hdenom;
-              double z0a = (-A * x0a - B * y0a - D) * Cdenom;
-              double z0b = (-A * x0b - B * y0b - D) * Cdenom;
-
-              addPoint(boundsInfo, bounds, new GeoPoint(x0a, y0a, z0a));
-              addPoint(boundsInfo, bounds, new GeoPoint(x0b, y0b, z0b));
-            }
-
-          } else {
-            //System.err.println(" Using the x quadratic");
-            // y = (-2J - Hx)/I
-
-            // Plug into the original equation:
-            // E x^2 + F [(-2J - Hx)/I]^2 + G x[(-2J - Hx)/I] - J = 0
-
-            // Multiply by I^2 to make manipulation easier
-            // E * I^2 * x^2 + F [(-2J - Hx)]^2 + GIx[(-2J - Hx)] - J * I^2 = 0
-            // Do the square
-            // E * I^2 * x^2 + F [ 4J^2 + 4JHx + H^2*x^2] + GI[(-2Jx - H*x^2)] - J * I^2 = 0
-
-            // Multiply it out
-            // E * I^2 * x^2 + 4FJ^2 + 4FJHx + F*H^2*x^2 - 2GIJx - HGI*x^2 - J * I^2 = 0
-            // Group:
-            // x^2 [E*I^2 - GHI + F*H^2] + x [4FJH - 2GIJ] + [4FJ^2 - J*I^2] = 0
-
-            // E x^2 + F y^2 + G xy + H x + I y + J = 0
-
-            a = E * I * I - G * H * I + F * H * H;
-            b = 4.0 * F * H * J - 2.0 * G * I * J;
-            c = 4.0 * F * J * J - J * I * I;
-
-            //System.out.println("a="+a+" b="+b+" c="+c);
-            double sqrtClause = b * b - 4.0 * a * c;
-            //System.out.println("sqrtClause="+sqrtClause);
-            if (Math.abs(sqrtClause) < MINIMUM_RESOLUTION_CUBED) {
-              //System.err.println(" One solution; sqrt clause was "+sqrtClause);
-              double x0 = -b / (2.0 * a);
-              double y0 = (-2.0 * J - H * x0) / I;
-              double z0 = (-A * x0 - B * y0 - D) / C;
-              // Verify that x&y fulfill the equation
-              // 2Ex^2 + 2Fy^2 + 2Gxy + Hx + Iy = 0
-              addPoint(boundsInfo, bounds, new GeoPoint(x0, y0, z0));
-            } else if (sqrtClause > 0.0) {
-              //System.err.println(" Two solutions");
-              double sqrtResult = Math.sqrt(sqrtClause);
-              double denom = 1.0 / (2.0 * a);
-              double Idenom = 1.0 / I;
-              double Cdenom = 1.0 / C;
-
-              double x0a = (-b + sqrtResult) * denom;
-              double x0b = (-b - sqrtResult) * denom;
-              double y0a = (-2.0 * J - H * x0a) * Idenom;
-              double y0b = (-2.0 * J - H * x0b) * Idenom;
-              double z0a = (-A * x0a - B * y0a - D) * Cdenom;
-              double z0b = (-A * x0b - B * y0b - D) * Cdenom;
-
-              addPoint(boundsInfo, bounds, new GeoPoint(x0a, y0a, z0a));
-              addPoint(boundsInfo, bounds, new GeoPoint(x0b, y0b, z0b));
-            }
-          }
-        }
-      }
-    }
-
-  }
-
-  /** Add a point to boundsInfo if within a specifically bounded area.
-   * @param boundsInfo is the object to be modified.
-   * @param bounds is the area that the point must be within.
-   * @param point is the point.
-   */
-  protected static void addPoint(final Bounds boundsInfo, final Membership[] bounds, final GeoPoint point) {
-    // Make sure the discovered point is within the bounds
-    for (Membership bound : bounds) {
-      if (!bound.isWithin(point))
-        return;
-    }
-    // Add the point
-    boundsInfo.addPoint(point);
-  }
-
-  /** Add a point to boundsInfo if within a specifically bounded area.
-   * @param boundsInfo is the object to be modified.
-   * @param bounds is the area that the point must be within.
-   * @param x is the x value.
-   * @param y is the y value.
-   * @param z is the z value.
-   */
-  /*
-  protected static void addPoint(final Bounds boundsInfo, final Membership[] bounds, final double x, final double y, final double z) {
-    //System.err.println(" Want to add point x="+x+" y="+y+" z="+z);
-    // Make sure the discovered point is within the bounds
-    for (Membership bound : bounds) {
-      if (!bound.isWithin(x, y, z))
-        return;
-    }
-    // Add the point
-    //System.err.println("  point added");
-    //System.out.println("Adding point x="+x+" y="+y+" z="+z);
-    boundsInfo.addPoint(x, y, z);
-  }
-  */
-
-  /**
-   * Determine whether the plane intersects another plane within the
-   * bounds provided.
-   *
-   * @param planetModel is the planet model to use in determining intersection.
-   * @param q                 is the other plane.
-   * @param notablePoints     are points to look at to disambiguate cases when the two planes are identical.
-   * @param moreNotablePoints are additional points to look at to disambiguate cases when the two planes are identical.
-   * @param bounds            is one part of the bounds.
-   * @param moreBounds        are more bounds.
-   * @return true if there's an intersection.
-   */
-  public boolean intersects(final PlanetModel planetModel, final Plane q, final GeoPoint[] notablePoints, final GeoPoint[] moreNotablePoints, final Membership[] bounds, final Membership... moreBounds) {
-    //System.err.println("Does plane "+this+" intersect with plane "+q);
-    // If the two planes are identical, then the math will find no points of intersection.
-    // So a special case of this is to check for plane equality.  But that is not enough, because
-    // what we really need at that point is to determine whether overlap occurs between the two parts of the intersection
-    // of plane and circle.  That is, are there *any* points on the plane that are within the bounds described?
-    if (isNumericallyIdentical(q)) {
-      //System.err.println(" Identical plane");
-      // The only way to efficiently figure this out will be to have a list of trial points available to evaluate.
-      // We look for any point that fulfills all the bounds.
-      for (GeoPoint p : notablePoints) {
-        if (meetsAllBounds(p, bounds, moreBounds)) {
-          //System.err.println("  found a notable point in bounds, so intersects");
-          return true;
-        }
-      }
-      for (GeoPoint p : moreNotablePoints) {
-        if (meetsAllBounds(p, bounds, moreBounds)) {
-          //System.err.println("  found a notable point in bounds, so intersects");
-          return true;
-        }
-      }
-      //System.err.println("  no notable points inside found; no intersection");
-      return false;
-    }
-    return findIntersections(planetModel, q, bounds, moreBounds).length > 0;
-  }
-
-  /**
-   * Returns true if this plane and the other plane are identical within the margin of error.
-   * @param p is the plane to compare against.
-   * @return true if the planes are numerically identical.
-   */
-  protected boolean isNumericallyIdentical(final Plane p) {
-    // We can get the correlation by just doing a parallel plane check.  If that passes, then compute a point on the plane
-    // (using D) and see if it also on the other plane.
-    if (Math.abs(this.y * p.z - this.z * p.y) >= MINIMUM_RESOLUTION)
-      return false;
-    if (Math.abs(this.z * p.x - this.x * p.z) >= MINIMUM_RESOLUTION)
-      return false;
-    if (Math.abs(this.x * p.y - this.y * p.x) >= MINIMUM_RESOLUTION)
-      return false;
-
-    // Now, see whether the parallel planes are in fact on top of one another.
-    // The math:
-    // We need a single point that fulfills:
-    // Ax + By + Cz + D = 0
-    // Pick:
-    // x0 = -(A * D) / (A^2 + B^2 + C^2)
-    // y0 = -(B * D) / (A^2 + B^2 + C^2)
-    // z0 = -(C * D) / (A^2 + B^2 + C^2)
-    // Check:
-    // A (x0) + B (y0) + C (z0) + D =? 0
-    // A (-(A * D) / (A^2 + B^2 + C^2)) + B (-(B * D) / (A^2 + B^2 + C^2)) + C (-(C * D) / (A^2 + B^2 + C^2)) + D ?= 0
-    // -D [ A^2 / (A^2 + B^2 + C^2) + B^2 / (A^2 + B^2 + C^2) + C^2 / (A^2 + B^2 + C^2)] + D ?= 0
-    // Yes.
-    final double denom = 1.0 / (p.x * p.x + p.y * p.y + p.z * p.z);
-    return evaluateIsZero(-p.x * p.D * denom, -p.y * p.D * denom, -p.z * p.D * denom);
-  }
-
-  /**
-   * Check if a vector meets the provided bounds.
-   * @param p is the vector.
-   * @param bounds are the bounds.
-   * @return true if the vector describes a point within the bounds.
-   */
-  protected static boolean meetsAllBounds(final Vector p, final Membership[] bounds) {
-    return meetsAllBounds(p.x, p.y, p.z, bounds);
-  }
-
-  /**
-   * Check if a vector meets the provided bounds.
-   * @param x is the x value.
-   * @param y is the y value.
-   * @param z is the z value.
-   * @param bounds are the bounds.
-   * @return true if the vector describes a point within the bounds.
-   */
-  protected static boolean meetsAllBounds(final double x, final double y, final double z, final Membership[] bounds) {
-    for (final Membership bound : bounds) {
-      if (!bound.isWithin(x,y,z))
-        return false;
-    }
-    return true;
-  }
-
-  /**
-   * Check if a vector meets the provided bounds.
-   * @param p is the vector.
-   * @param bounds are the bounds.
-   * @param moreBounds are an additional set of bounds.
-   * @return true if the vector describes a point within the bounds.
-   */
-  protected static boolean meetsAllBounds(final Vector p, final Membership[] bounds, final Membership[] moreBounds) {
-    return meetsAllBounds(p.x, p.y, p.z, bounds, moreBounds);
-  }
-
-  /**
-   * Check if a vector meets the provided bounds.
-   * @param x is the x value.
-   * @param y is the y value.
-   * @param z is the z value.
-   * @param bounds are the bounds.
-   * @param moreBounds are an additional set of bounds.
-   * @return true if the vector describes a point within the bounds.
-   */
-  protected static boolean meetsAllBounds(final double x, final double y, final double z, final Membership[] bounds,
-                                          final Membership[] moreBounds) {
-    return meetsAllBounds(x,y,z, bounds) && meetsAllBounds(x,y,z, moreBounds);
-  }
-
-  /**
-   * Find a sample point on the intersection between two planes and the world.
-   * @param planetModel is the planet model.
-   * @param q is the second plane to consider.
-   * @return a sample point that is on the intersection between the two planes and the world.
-   */
-  public GeoPoint getSampleIntersectionPoint(final PlanetModel planetModel, final Plane q) {
-    final GeoPoint[] intersections = findIntersections(planetModel, q, NO_BOUNDS, NO_BOUNDS);
-    if (intersections.length == 0)
-      return null;
-    return intersections[0];
-  }
-
-  @Override
-  public String toString() {
-    return "[A=" + x + ", B=" + y + "; C=" + z + "; D=" + D + "]";
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!super.equals(o))
-      return false;
-    if (!(o instanceof Plane))
-      return false;
-    Plane other = (Plane) o;
-    return other.D == D;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    long temp;
-    temp = Double.doubleToLongBits(D);
-    result = 31 * result + (int) (temp ^ (temp >>> 32));
-    return result;
-  }
-}


[09/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 0093e26)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBBoxFactory.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBBoxFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBBoxFactory.java
new file mode 100755
index 0000000..de7493e
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBBoxFactory.java
@@ -0,0 +1,111 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Factory for {@link GeoBBox}.
+ *
+ * @lucene.experimental
+ */
+public class GeoBBoxFactory {
+  private GeoBBoxFactory() {
+  }
+
+  /**
+   * Create a geobbox of the right kind given the specified bounds.
+   *
+   * @param planetModel is the planet model
+   * @param topLat    is the top latitude
+   * @param bottomLat is the bottom latitude
+   * @param leftLon   is the left longitude
+   * @param rightLon  is the right longitude
+   * @return a GeoBBox corresponding to what was specified.
+   */
+  public static GeoBBox makeGeoBBox(final PlanetModel planetModel, double topLat, double bottomLat, double leftLon, double rightLon) {
+    //System.err.println("Making rectangle for topLat="+topLat*180.0/Math.PI+", bottomLat="+bottomLat*180.0/Math.PI+", leftLon="+leftLon*180.0/Math.PI+", rightlon="+rightLon*180.0/Math.PI);
+    if (topLat > Math.PI * 0.5)
+      topLat = Math.PI * 0.5;
+    if (bottomLat < -Math.PI * 0.5)
+      bottomLat = -Math.PI * 0.5;
+    if (leftLon < -Math.PI)
+      leftLon = -Math.PI;
+    if (rightLon > Math.PI)
+      rightLon = Math.PI;
+    if (Math.abs(leftLon + Math.PI) < Vector.MINIMUM_RESOLUTION && Math.abs(rightLon - Math.PI) < Vector.MINIMUM_RESOLUTION) {
+      if (Math.abs(topLat - Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION && Math.abs(bottomLat + Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION)
+        return new GeoWorld(planetModel);
+      if (Math.abs(topLat - bottomLat) < Vector.MINIMUM_RESOLUTION) {
+        if (Math.abs(topLat - Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION || Math.abs(topLat + Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION)
+          return new GeoDegeneratePoint(planetModel, topLat, 0.0);
+        return new GeoDegenerateLatitudeZone(planetModel, topLat);
+      }
+      if (Math.abs(topLat - Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION)
+        return new GeoNorthLatitudeZone(planetModel, bottomLat);
+      else if (Math.abs(bottomLat + Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION)
+        return new GeoSouthLatitudeZone(planetModel, topLat);
+      return new GeoLatitudeZone(planetModel, topLat, bottomLat);
+    }
+    //System.err.println(" not latitude zone");
+    double extent = rightLon - leftLon;
+    if (extent < 0.0)
+      extent += Math.PI * 2.0;
+    if (topLat == Math.PI * 0.5 && bottomLat == -Math.PI * 0.5) {
+      if (Math.abs(leftLon - rightLon) < Vector.MINIMUM_RESOLUTION)
+        return new GeoDegenerateLongitudeSlice(planetModel, leftLon);
+
+      if (extent >= Math.PI)
+        return new GeoWideLongitudeSlice(planetModel, leftLon, rightLon);
+
+      return new GeoLongitudeSlice(planetModel, leftLon, rightLon);
+    }
+    //System.err.println(" not longitude slice");
+    if (Math.abs(leftLon - rightLon) < Vector.MINIMUM_RESOLUTION) {
+      if (Math.abs(topLat - bottomLat) < Vector.MINIMUM_RESOLUTION)
+        return new GeoDegeneratePoint(planetModel, topLat, leftLon);
+      return new GeoDegenerateVerticalLine(planetModel, topLat, bottomLat, leftLon);
+    }
+    //System.err.println(" not vertical line");
+    if (extent >= Math.PI) {
+      if (Math.abs(topLat - bottomLat) < Vector.MINIMUM_RESOLUTION) {
+        //System.err.println(" wide degenerate line");
+        return new GeoWideDegenerateHorizontalLine(planetModel, topLat, leftLon, rightLon);
+      }
+      if (Math.abs(topLat - Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION) {
+        return new GeoWideNorthRectangle(planetModel, bottomLat, leftLon, rightLon);
+      } else if (Math.abs(bottomLat + Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION) {
+        return new GeoWideSouthRectangle(planetModel, topLat, leftLon, rightLon);
+      }
+      //System.err.println(" wide rect");
+      return new GeoWideRectangle(planetModel, topLat, bottomLat, leftLon, rightLon);
+    }
+    if (Math.abs(topLat - bottomLat) < Vector.MINIMUM_RESOLUTION) {
+      if (Math.abs(topLat - Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION || Math.abs(topLat + Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION) {
+        return new GeoDegeneratePoint(planetModel, topLat, 0.0);
+      }
+      //System.err.println(" horizontal line");
+      return new GeoDegenerateHorizontalLine(planetModel, topLat, leftLon, rightLon);
+    }
+    if (Math.abs(topLat - Math.PI * 0.5) < Vector.MINIMUM_RESOLUTION) {
+      return new GeoNorthRectangle(planetModel, bottomLat, leftLon, rightLon);
+    } else if (Math.abs(bottomLat + Math.PI * 0.5) <  Vector.MINIMUM_RESOLUTION) {
+      return new GeoSouthRectangle(planetModel, topLat, leftLon, rightLon);
+    }
+    //System.err.println(" rectangle");
+    return new GeoRectangle(planetModel, topLat, bottomLat, leftLon, rightLon);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseBBox.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseBBox.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseBBox.java
new file mode 100644
index 0000000..7190cdc
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseBBox.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.spatial3d.geom;
+
+/**
+ * All bounding box shapes can derive from this base class, which furnishes
+ * some common code
+ *
+ * @lucene.internal
+ */
+public abstract class GeoBaseBBox extends GeoBaseMembershipShape implements GeoBBox {
+
+  /** Construct, given planet model.
+   *@param planetModel is the planet model.
+   */
+  public GeoBaseBBox(final PlanetModel planetModel) {
+    super(planetModel);
+  }
+
+  // Signals for relationship of edge points to shape
+  
+  /** All edgepoints inside shape */
+  protected final static int ALL_INSIDE = 0;
+  /** Some edgepoints inside shape */
+  protected final static int SOME_INSIDE = 1;
+  /** No edgepoints inside shape */
+  protected final static int NONE_INSIDE = 2;
+
+  /** Determine the relationship between this BBox and the provided
+   * shape's edgepoints.
+   *@param path is the shape.
+   *@return the relationship.
+   */
+  protected int isShapeInsideBBox(final GeoShape path) {
+    final GeoPoint[] pathPoints = path.getEdgePoints();
+    boolean foundOutside = false;
+    boolean foundInside = false;
+    for (GeoPoint p : pathPoints) {
+      if (isWithin(p)) {
+        foundInside = true;
+      } else {
+        foundOutside = true;
+      }
+      if (foundInside && foundOutside) {
+        return SOME_INSIDE;
+      }
+    }
+    if (!foundInside && !foundOutside)
+      return NONE_INSIDE;
+    if (foundInside && !foundOutside)
+      return ALL_INSIDE;
+    if (foundOutside && !foundInside)
+      return NONE_INSIDE;
+    return SOME_INSIDE;
+  }
+
+}
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseCircle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseCircle.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseCircle.java
new file mode 100644
index 0000000..75219fd
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseCircle.java
@@ -0,0 +1,34 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * GeoCircles have all the characteristics of GeoBaseDistanceShapes, plus GeoSizeable.
+ *
+ * @lucene.experimental
+ */
+public abstract class GeoBaseCircle extends GeoBaseDistanceShape implements GeoCircle {
+
+  /** Constructor.
+   *@param planetModel is the planet model to use.
+   */
+  public GeoBaseCircle(final PlanetModel planetModel) {
+    super(planetModel);
+  }
+
+}
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseDistanceShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseDistanceShape.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseDistanceShape.java
new file mode 100644
index 0000000..39dcf96
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseDistanceShape.java
@@ -0,0 +1,56 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Distance shapes have capabilities of both geohashing and distance
+ * computation (which also includes point membership determination).
+ *
+ * @lucene.experimental
+ */
+public abstract class GeoBaseDistanceShape extends GeoBaseMembershipShape implements GeoDistanceShape {
+
+  /** Constructor.
+   *@param planetModel is the planet model to use.
+   */
+  public GeoBaseDistanceShape(final PlanetModel planetModel) {
+    super(planetModel);
+  }
+
+  @Override
+  public boolean isWithin(Vector point) {
+    return isWithin(point.x, point.y, point.z);
+  }
+
+  @Override
+  public double computeDistance(final DistanceStyle distanceStyle, final GeoPoint point) {
+    return computeDistance(distanceStyle, point.x, point.y, point.z);
+  }
+
+  @Override
+  public double computeDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    if (!isWithin(x,y,z)) {
+      return Double.MAX_VALUE;
+    }
+    return distance(distanceStyle, x, y, z);
+  }
+
+  /** Called by a {@code computeDistance} method if X/Y/Z is not within this shape. */
+  protected abstract double distance(final DistanceStyle distanceStyle, final double x, final double y, final double z);
+
+}
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseMembershipShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseMembershipShape.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseMembershipShape.java
new file mode 100644
index 0000000..831a7c6
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseMembershipShape.java
@@ -0,0 +1,56 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Membership shapes have capabilities of both geohashing and membership
+ * determination.  This is a useful baseclass for them.
+ *
+ * @lucene.experimental
+ */
+public abstract class GeoBaseMembershipShape extends GeoBaseShape implements GeoMembershipShape {
+
+  /** Constructor.
+   *@param planetModel is the planet model to use.
+   */
+  public GeoBaseMembershipShape(final PlanetModel planetModel) {
+    super(planetModel);
+  }
+
+  @Override
+  public boolean isWithin(Vector point) {
+    return isWithin(point.x, point.y, point.z);
+  }
+
+  @Override
+  public double computeOutsideDistance(final DistanceStyle distanceStyle, final GeoPoint point) {
+    return computeOutsideDistance(distanceStyle, point.x, point.y, point.z);
+  }
+
+  @Override
+  public double computeOutsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    if (isWithin(x,y,z)) {
+      return 0.0;
+    }
+    return outsideDistance(distanceStyle, x,y,z);
+  }
+
+  /** Called by a {@code computeOutsideDistance} method if X/Y/Z is not within this shape. */
+  protected abstract double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z);
+
+}
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBasePolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBasePolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBasePolygon.java
new file mode 100644
index 0000000..ba221ae
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBasePolygon.java
@@ -0,0 +1,34 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * GeoBasePolygon objects are the base class of most GeoPolygon objects.
+ *
+ * @lucene.experimental
+ */
+public abstract class GeoBasePolygon extends GeoBaseMembershipShape implements GeoPolygon {
+
+  /** Constructor.
+   *@param planetModel is the planet model to use.
+   */
+  public GeoBasePolygon(final PlanetModel planetModel) {
+    super(planetModel);
+  }
+
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseShape.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseShape.java
new file mode 100644
index 0000000..54896fc
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBaseShape.java
@@ -0,0 +1,59 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Base extended shape object.
+ *
+ * @lucene.internal
+ */
+public abstract class GeoBaseShape extends BasePlanetObject implements GeoShape {
+
+  /** Constructor.
+   *@param planetModel is the planet model to use.
+   */
+  public GeoBaseShape(final PlanetModel planetModel) {
+    super(planetModel);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    if (isWithin(planetModel.NORTH_POLE)) {
+      bounds.noTopLatitudeBound().noLongitudeBound()
+        .addPoint(planetModel.NORTH_POLE);
+    }
+    if (isWithin(planetModel.SOUTH_POLE)) {
+      bounds.noBottomLatitudeBound().noLongitudeBound()
+        .addPoint(planetModel.SOUTH_POLE);
+    }
+    if (isWithin(planetModel.MIN_X_POLE)) {
+      bounds.addPoint(planetModel.MIN_X_POLE);
+    }
+    if (isWithin(planetModel.MAX_X_POLE)) {
+      bounds.addPoint(planetModel.MAX_X_POLE);
+    }
+    if (isWithin(planetModel.MIN_Y_POLE)) {
+      bounds.addPoint(planetModel.MIN_Y_POLE);
+    }
+    if (isWithin(planetModel.MAX_Y_POLE)) {
+      bounds.addPoint(planetModel.MAX_Y_POLE);
+    }
+  }
+
+}
+
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCircle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCircle.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCircle.java
new file mode 100755
index 0000000..b05dff6
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCircle.java
@@ -0,0 +1,25 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Interface describing circular area with a center and radius.
+ *
+ * @lucene.experimental
+ */
+public interface GeoCircle extends GeoDistanceShape, GeoSizeable {
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCircleFactory.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCircleFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCircleFactory.java
new file mode 100644
index 0000000..ee75179
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCircleFactory.java
@@ -0,0 +1,43 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Class which constructs a GeoCircle representing an arbitrary circle.
+ *
+ * @lucene.experimental
+ */
+public class GeoCircleFactory {
+  private GeoCircleFactory() {
+  }
+
+  /**
+   * Create a GeoCircle of the right kind given the specified bounds.
+   * @param planetModel is the planet model.
+   * @param latitude is the center latitude.
+   * @param longitude is the center longitude.
+   * @param radius is the radius angle.
+   * @return a GeoCircle corresponding to what was specified.
+   */
+  public static GeoCircle makeGeoCircle(final PlanetModel planetModel, final double latitude, final double longitude, final double radius) {
+    if (radius < Vector.MINIMUM_RESOLUTION) {
+      return new GeoDegeneratePoint(planetModel, latitude, longitude);
+    }
+    return new GeoStandardCircle(planetModel, latitude, longitude, radius);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCompositeMembershipShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCompositeMembershipShape.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCompositeMembershipShape.java
new file mode 100755
index 0000000..9747eda
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCompositeMembershipShape.java
@@ -0,0 +1,117 @@
+/*
+ * 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.spatial3d.geom;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * GeoComposite is a set of GeoMembershipShape's, treated as a unit.
+ *
+ * @lucene.experimental
+ */
+public class GeoCompositeMembershipShape implements GeoMembershipShape {
+  /** The list of shapes. */
+  protected final List<GeoMembershipShape> shapes = new ArrayList<GeoMembershipShape>();
+
+  /** Constructor.
+   */
+  public GeoCompositeMembershipShape() {
+  }
+
+  /**
+   * Add a shape to the composite.
+   *@param shape is the shape to add.
+   */
+  public void addShape(final GeoMembershipShape shape) {
+    shapes.add(shape);
+  }
+
+  @Override
+  public boolean isWithin(final Vector point) {
+    return isWithin(point.x, point.y, point.z);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    for (GeoMembershipShape shape : shapes) {
+      if (shape.isWithin(x, y, z))
+        return true;
+    }
+    return false;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return shapes.get(0).getEdgePoints();
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    for (GeoMembershipShape shape : shapes) {
+      if (shape.intersects(p, notablePoints, bounds))
+        return true;
+    }
+    return false;
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    for (GeoMembershipShape shape : shapes) {
+      shape.getBounds(bounds);
+    }
+  }
+
+  @Override
+  public double computeOutsideDistance(final DistanceStyle distanceStyle, final GeoPoint point) {
+    return computeOutsideDistance(distanceStyle, point.x, point.y, point.z);
+  }
+
+  @Override
+  public double computeOutsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    if (isWithin(x,y,z))
+      return 0.0;
+    double distance = Double.MAX_VALUE;
+    for (GeoMembershipShape shape : shapes) {
+      final double normalDistance = shape.computeOutsideDistance(distanceStyle, x, y, z);
+      if (normalDistance < distance) {
+        distance = normalDistance;
+      }
+    }
+    return distance;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoCompositeMembershipShape))
+      return false;
+    GeoCompositeMembershipShape other = (GeoCompositeMembershipShape) o;
+
+    return super.equals(o) && shapes.equals(other.shapes);
+  }
+
+  @Override
+  public int hashCode() {
+    return super.hashCode() * 31 + shapes.hashCode();//TODO cache
+  }
+
+  @Override
+  public String toString() {
+    return "GeoCompositeMembershipShape: {" + shapes + '}';
+  }
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCompositePolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCompositePolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCompositePolygon.java
new file mode 100644
index 0000000..920d3fb
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoCompositePolygon.java
@@ -0,0 +1,31 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * GeoCompositePolygon is a specific implementation of GeoMembershipShape, which implements GeoPolygon explicitly.
+ *
+ * @lucene.experimental
+ */
+public class GeoCompositePolygon extends GeoCompositeMembershipShape implements GeoPolygon {
+  /** Constructor.
+   */
+  public GeoCompositePolygon() {
+  }
+
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoConvexPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoConvexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoConvexPolygon.java
new file mode 100755
index 0000000..fb024b6
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoConvexPolygon.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.spatial3d.geom;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.List;
+
+/**
+ * GeoConvexPolygon objects are generic building blocks of more complex structures.
+ * The only restrictions on these objects are: (1) they must be convex; (2) they must have
+ * a maximum extent no larger than PI.  Violating either one of these limits will
+ * cause the logic to fail.
+ *
+ * @lucene.experimental
+ */
+public class GeoConvexPolygon extends GeoBasePolygon {
+  /** The list of polygon points */
+  protected final List<GeoPoint> points;
+  /** A bitset describing, for each edge, whether it is internal or not */
+  protected final BitSet isInternalEdges;
+
+  /** A list of edges */
+  protected SidedPlane[] edges = null;
+  /** The set of notable points for each edge */
+  protected GeoPoint[][] notableEdgePoints = null;
+  /** A point which is on the boundary of the polygon */
+  protected GeoPoint[] edgePoints = null;
+  /** Tracking the maximum distance we go at any one time, so to be sure it's legal */
+  protected double fullDistance = 0.0;
+  /** Set to true when the polygon is complete */
+  protected boolean isDone = false;
+  
+  /**
+   * Create a convex polygon from a list of points.  The first point must be on the
+   * external edge.
+   *@param planetModel is the planet model.
+   *@param pointList is the list of points to create the polygon from.
+   */
+  public GeoConvexPolygon(final PlanetModel planetModel, final List<GeoPoint> pointList) {
+    super(planetModel);
+    this.points = pointList;
+    this.isInternalEdges = new BitSet();
+    done(false);
+  }
+
+  /**
+   * Create a convex polygon from a list of points, keeping track of which boundaries
+   * are internal.  This is used when creating a polygon as a building block for another shape.
+   *@param planetModel is the planet model.
+   *@param pointList is the set of points to create the polygon from.
+   *@param internalEdgeFlags is a bitset describing whether each edge is internal or not.
+   *@param returnEdgeInternal is true when the final return edge is an internal one.
+   */
+  public GeoConvexPolygon(final PlanetModel planetModel, final List<GeoPoint> pointList, final BitSet internalEdgeFlags,
+                          final boolean returnEdgeInternal) {
+    super(planetModel);
+    this.points = pointList;
+    this.isInternalEdges = internalEdgeFlags;
+    done(returnEdgeInternal);
+  }
+
+  /**
+   * Create a convex polygon, with a starting latitude and longitude.
+   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
+   *@param planetModel is the planet model.
+   *@param startLatitude is the latitude of the first point.
+   *@param startLongitude is the longitude of the first point.
+   */
+  public GeoConvexPolygon(final PlanetModel planetModel, final double startLatitude, final double startLongitude) {
+    super(planetModel);
+    points = new ArrayList<>();
+    isInternalEdges = new BitSet();
+    points.add(new GeoPoint(planetModel, startLatitude, startLongitude));
+  }
+
+  /**
+   * Add a point to the polygon.
+   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
+   *
+   * @param latitude       is the latitude of the next point.
+   * @param longitude      is the longitude of the next point.
+   * @param isInternalEdge is true if the edge just added with this point should be considered "internal", and not
+   *                       intersected as part of the intersects() operation.
+   */
+  public void addPoint(final double latitude, final double longitude, final boolean isInternalEdge) {
+    if (isDone)
+      throw new IllegalStateException("Can't call addPoint() if done() already called");
+    if (isInternalEdge)
+      isInternalEdges.set(points.size() - 1);
+    points.add(new GeoPoint(planetModel, latitude, longitude));
+  }
+
+  /**
+   * Finish the polygon, by connecting the last added point with the starting point.
+   *@param isInternalReturnEdge is true if the return edge (back to start) is an internal one.
+   */
+  public void done(final boolean isInternalReturnEdge) {
+    if (isDone)
+      throw new IllegalStateException("Can't call done() more than once");
+    // If fewer than 3 points, can't do it.
+    if (points.size() < 3)
+      throw new IllegalArgumentException("Polygon needs at least three points.");
+
+    if (isInternalReturnEdge)
+      isInternalEdges.set(points.size() - 1);
+
+    isDone = true;
+    
+    // Time to construct the planes.  If the polygon is truly convex, then any adjacent point
+    // to a segment can provide an interior measurement.
+    edges = new SidedPlane[points.size()];
+    notableEdgePoints = new GeoPoint[points.size()][];
+
+    for (int i = 0; i < points.size(); i++) {
+      final GeoPoint start = points.get(i);
+      final GeoPoint end = points.get(legalIndex(i + 1));
+      final double distance = start.arcDistance(end);
+      if (distance > fullDistance)
+        fullDistance = distance;
+      final GeoPoint check = points.get(legalIndex(i + 2));
+      final SidedPlane sp = new SidedPlane(check, start, end);
+      //System.out.println("Created edge "+sp+" using start="+start+" end="+end+" check="+check);
+      edges[i] = sp;
+      notableEdgePoints[i] = new GeoPoint[]{start, end};
+    }
+    createCenterPoint();
+  }
+
+  /** Compute a reasonable center point.
+   */
+  protected void createCenterPoint() {
+    // In order to naively confirm that the polygon is convex, I would need to
+    // check every edge, and verify that every point (other than the edge endpoints)
+    // is within the edge's sided plane.  This is an order n^2 operation.  That's still
+    // not wrong, though, because everything else about polygons has a similar cost.
+    for (int edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
+      final SidedPlane edge = edges[edgeIndex];
+      for (int pointIndex = 0; pointIndex < points.size(); pointIndex++) {
+        if (pointIndex != edgeIndex && pointIndex != legalIndex(edgeIndex + 1)) {
+          if (!edge.isWithin(points.get(pointIndex)))
+            throw new IllegalArgumentException("Polygon is not convex: Point " + points.get(pointIndex) + " Edge " + edge);
+        }
+      }
+    }
+    edgePoints = new GeoPoint[]{points.get(0)};
+  }
+
+  /** Compute a legal point index from a possibly illegal one, that may have wrapped.
+   *@param index is the index.
+   *@return the normalized index.
+   */
+  protected int legalIndex(int index) {
+    while (index >= points.size())
+      index -= points.size();
+    return index;
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    for (final SidedPlane edge : edges) {
+      if (!edge.isWithin(x, y, z))
+        return false;
+    }
+    return true;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    //System.err.println("Checking for polygon intersection with plane "+p+"...");
+    for (int edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
+      final SidedPlane edge = edges[edgeIndex];
+      final GeoPoint[] points = this.notableEdgePoints[edgeIndex];
+      if (!isInternalEdges.get(edgeIndex)) {
+        //System.err.println(" non-internal edge "+edge);
+        // Edges flagged as 'internal only' are excluded from the matching
+        // Construct boundaries
+        final Membership[] membershipBounds = new Membership[edges.length - 1];
+        int count = 0;
+        for (int otherIndex = 0; otherIndex < edges.length; otherIndex++) {
+          if (otherIndex != edgeIndex) {
+            membershipBounds[count++] = edges[otherIndex];
+          }
+        }
+        if (edge.intersects(planetModel, p, notablePoints, points, bounds, membershipBounds)) {
+          //System.err.println(" intersects!");
+          return true;
+        }
+      }
+    }
+    //System.err.println(" no intersection");
+    return false;
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+
+    // Add all the points
+    for (final GeoPoint point : points) {
+      bounds.addPoint(point);
+    }
+
+    // Add planes with membership.
+    for (int edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
+      final SidedPlane edge = edges[edgeIndex];
+      // Construct boundaries
+      final Membership[] membershipBounds = new Membership[edges.length - 1];
+      int count = 0;
+      for (int otherIndex = 0; otherIndex < edges.length; otherIndex++) {
+        if (otherIndex != edgeIndex) {
+          membershipBounds[count++] = edges[otherIndex];
+        }
+      }
+      bounds.addPlane(planetModel, edge, membershipBounds);
+    }
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    double minimumDistance = Double.MAX_VALUE;
+    for (final GeoPoint edgePoint : points) {
+      final double newDist = distanceStyle.computeDistance(edgePoint, x,y,z);
+      if (newDist < minimumDistance) {
+        minimumDistance = newDist;
+      }
+    }
+    for (int edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
+      final Plane edgePlane = edges[edgeIndex];
+      final Membership[] membershipBounds = new Membership[edges.length - 1];
+      int count = 0;
+      for (int otherIndex = 0; otherIndex < edges.length; otherIndex++) {
+        if (otherIndex != edgeIndex) {
+          membershipBounds[count++] = edges[otherIndex];
+        }
+      }
+      final double newDist = distanceStyle.computeDistance(planetModel, edgePlane, x, y, z, membershipBounds);
+      if (newDist < minimumDistance) {
+        minimumDistance = newDist;
+      }
+    }
+    return minimumDistance;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoConvexPolygon))
+      return false;
+    GeoConvexPolygon other = (GeoConvexPolygon) o;
+    if (!super.equals(other))
+      return false;
+    if (!other.isInternalEdges.equals(isInternalEdges))
+      return false;
+    return (other.points.equals(points));
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + points.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoConvexPolygon: {planetmodel=" + planetModel + ", points=" + points + "}";
+  }
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateHorizontalLine.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateHorizontalLine.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateHorizontalLine.java
new file mode 100644
index 0000000..b7de0c2
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateHorizontalLine.java
@@ -0,0 +1,215 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Degenerate bounding box limited on two sides (left lon, right lon).
+ * The left-right maximum extent for this shape is PI; for anything larger, use
+ * GeoWideDegenerateHorizontalLine.
+ *
+ * @lucene.internal
+ */
+public class GeoDegenerateHorizontalLine extends GeoBaseBBox {
+  /** Latitude of horizontal line */
+  protected final double latitude;
+  /** Left bounding longitude of line */
+  protected final double leftLon;
+  /** Right bounding longitude of line */
+  protected final double rightLon;
+
+  /** Left hand endpoint of line */
+  protected final GeoPoint LHC;
+  /** Right hand endpoint of line */
+  protected final GeoPoint RHC;
+
+  /** The plane describing the line */
+  protected final Plane plane;
+  /** The left side end plane */
+  protected final SidedPlane leftPlane;
+  /** The right side end plane */
+  protected final SidedPlane rightPlane;
+
+  /** Notable points for the line */
+  protected final GeoPoint[] planePoints;
+
+  /** Center of line */
+  protected final GeoPoint centerPoint;
+  /** A point that's on the line */
+  protected final GeoPoint[] edgePoints;
+
+  /**
+   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
+   *@param planetModel is the planet model.
+   *@param latitude is the latitude of the line.
+   *@param leftLon is the left end longitude.
+   *@param rightLon is the right end longitude.
+   */
+  public GeoDegenerateHorizontalLine(final PlanetModel planetModel, final double latitude, final double leftLon, double rightLon) {
+    super(planetModel);
+    // Argument checking
+    if (latitude > Math.PI * 0.5 || latitude < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Latitude out of range");
+    if (leftLon < -Math.PI || leftLon > Math.PI)
+      throw new IllegalArgumentException("Left longitude out of range");
+    if (rightLon < -Math.PI || rightLon > Math.PI)
+      throw new IllegalArgumentException("Right longitude out of range");
+    double extent = rightLon - leftLon;
+    if (extent < 0.0) {
+      extent += 2.0 * Math.PI;
+    }
+    if (extent > Math.PI)
+      throw new IllegalArgumentException("Width of rectangle too great");
+
+    this.latitude = latitude;
+    this.leftLon = leftLon;
+    this.rightLon = rightLon;
+
+    final double sinLatitude = Math.sin(latitude);
+    final double cosLatitude = Math.cos(latitude);
+    final double sinLeftLon = Math.sin(leftLon);
+    final double cosLeftLon = Math.cos(leftLon);
+    final double sinRightLon = Math.sin(rightLon);
+    final double cosRightLon = Math.cos(rightLon);
+
+    // Now build the two points
+    this.LHC = new GeoPoint(planetModel, sinLatitude, sinLeftLon, cosLatitude, cosLeftLon, latitude, leftLon);
+    this.RHC = new GeoPoint(planetModel, sinLatitude, sinRightLon, cosLatitude, cosRightLon, latitude, rightLon);
+
+    this.plane = new Plane(planetModel, sinLatitude);
+
+    // Normalize
+    while (leftLon > rightLon) {
+      rightLon += Math.PI * 2.0;
+    }
+    final double middleLon = (leftLon + rightLon) * 0.5;
+    final double sinMiddleLon = Math.sin(middleLon);
+    final double cosMiddleLon = Math.cos(middleLon);
+
+    this.centerPoint = new GeoPoint(planetModel, sinLatitude, sinMiddleLon, cosLatitude, cosMiddleLon);
+    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
+    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
+
+    this.planePoints = new GeoPoint[]{LHC, RHC};
+
+    this.edgePoints = new GeoPoint[]{centerPoint};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    double newTopLat = latitude + angle;
+    double newBottomLat = latitude - angle;
+    // Figuring out when we escalate to a special case requires some prefiguring
+    double currentLonSpan = rightLon - leftLon;
+    if (currentLonSpan < 0.0)
+      currentLonSpan += Math.PI * 2.0;
+    double newLeftLon = leftLon - angle;
+    double newRightLon = rightLon + angle;
+    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
+      newLeftLon = -Math.PI;
+      newRightLon = Math.PI;
+    }
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return plane.evaluateIsZero(x, y, z) &&
+        leftPlane.isWithin(x, y, z) &&
+        rightPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public double getRadius() {
+    double topAngle = centerPoint.arcDistance(RHC);
+    double bottomAngle = centerPoint.arcDistance(LHC);
+    return Math.max(topAngle, bottomAngle);
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    return centerPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return p.intersects(planetModel, plane, notablePoints, planePoints, bounds, leftPlane, rightPlane);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds.addHorizontalPlane(planetModel, latitude, plane, leftPlane, rightPlane)
+      .addPoint(LHC).addPoint(RHC);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    //System.err.println("getting relationship between "+this+" and "+path);
+    if (path.intersects(plane, planePoints, leftPlane, rightPlane)) {
+      //System.err.println(" overlaps");
+      return OVERLAPS;
+    }
+
+    if (path.isWithin(centerPoint)) {
+      //System.err.println(" contains");
+      return CONTAINS;
+    }
+
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    final double distance = distanceStyle.computeDistance(planetModel, plane, x,y,z, leftPlane, rightPlane);
+    
+    final double LHCDistance = distanceStyle.computeDistance(LHC, x,y,z);
+    final double RHCDistance = distanceStyle.computeDistance(RHC, x,y,z);
+    
+    return Math.min(
+      distance,
+      Math.min(LHCDistance, RHCDistance));
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoDegenerateHorizontalLine))
+      return false;
+    GeoDegenerateHorizontalLine other = (GeoDegenerateHorizontalLine) o;
+    return super.equals(other) && other.LHC.equals(LHC) && other.RHC.equals(RHC);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + LHC.hashCode();
+    result = 31 * result + RHC.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoDegenerateHorizontalLine: {planetmodel="+planetModel+", latitude=" + latitude + "(" + latitude * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightLon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
+  }
+}
+  
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateLatitudeZone.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateLatitudeZone.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateLatitudeZone.java
new file mode 100644
index 0000000..e794123
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateLatitudeZone.java
@@ -0,0 +1,138 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * This GeoBBox represents an area rectangle of one specific latitude with
+ * no longitude bounds.
+ *
+ * @lucene.internal
+ */
+public class GeoDegenerateLatitudeZone extends GeoBaseBBox {
+  /** The latitude */
+  protected final double latitude;
+  /** Sine of the latitude */
+  protected final double sinLatitude;
+  /** Plane describing the latitude zone */
+  protected final Plane plane;
+  /** A point on the world that's also on the zone */
+  protected final GeoPoint interiorPoint;
+  /** An array consisting of the interiorPoint */
+  protected final GeoPoint[] edgePoints;
+  /** No notable points */
+  protected final static GeoPoint[] planePoints = new GeoPoint[0];
+
+  /** Constructor.
+   *@param planetModel is the planet model to use.
+   *@param latitude is the latitude of the latitude zone.
+   */
+  public GeoDegenerateLatitudeZone(final PlanetModel planetModel, final double latitude) {
+    super(planetModel);
+    this.latitude = latitude;
+
+    this.sinLatitude = Math.sin(latitude);
+    double cosLatitude = Math.cos(latitude);
+    this.plane = new Plane(planetModel, sinLatitude);
+    // Compute an interior point.
+    interiorPoint = new GeoPoint(planetModel, sinLatitude, 0.0, cosLatitude, 1.0);
+    edgePoints = new GeoPoint[]{interiorPoint};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    double newTopLat = latitude + angle;
+    double newBottomLat = latitude - angle;
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, -Math.PI, Math.PI);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return Math.abs(z - this.sinLatitude) < 1e-10;
+  }
+
+  @Override
+  public double getRadius() {
+    return Math.PI;
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    // Totally arbitrary
+    return interiorPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return p.intersects(planetModel, plane, notablePoints, planePoints, bounds);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds.noLongitudeBound()
+      .addHorizontalPlane(planetModel, latitude, plane);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    // Second, the shortcut of seeing whether endpoints are in/out is not going to
+    // work with no area endpoints.  So we rely entirely on intersections.
+    //System.out.println("Got here! latitude="+latitude+" path="+path);
+
+    if (path.intersects(plane, planePoints)) {
+      return OVERLAPS;
+    }
+
+    if (path.isWithin(interiorPoint)) {
+      return CONTAINS;
+    }
+
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    return distanceStyle.computeDistance(planetModel, plane, x,y,z);
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoDegenerateLatitudeZone))
+      return false;
+    GeoDegenerateLatitudeZone other = (GeoDegenerateLatitudeZone) o;
+    return super.equals(other) && other.latitude == latitude;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    long temp = Double.doubleToLongBits(latitude);
+    result = 31 * result + (int) (temp ^ (temp >>> 32));
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoDegenerateLatitudeZone: {planetmodel="+planetModel+", lat=" + latitude + "(" + latitude * 180.0 / Math.PI + ")}";
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateLongitudeSlice.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateLongitudeSlice.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateLongitudeSlice.java
new file mode 100644
index 0000000..0bb7b90
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateLongitudeSlice.java
@@ -0,0 +1,153 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Degenerate longitude slice.
+ *
+ * @lucene.internal
+ */
+public class GeoDegenerateLongitudeSlice extends GeoBaseBBox {
+  /** The longitude of the slice */
+  protected final double longitude;
+
+  /** The bounding plane for the slice (through both poles, perpendicular to the slice) */
+  protected final SidedPlane boundingPlane;
+  /** The plane of the slice */
+  protected final Plane plane;
+  /** A point on the slice */
+  protected final GeoPoint interiorPoint;
+  /** An array consisting of the one point chosen on the slice */
+  protected final GeoPoint[] edgePoints;
+  /** Notable points for the slice (north and south poles) */
+  protected final GeoPoint[] planePoints;
+
+  /**
+   * Accepts only values in the following ranges: lon: {@code -PI -> PI}
+   */
+  public GeoDegenerateLongitudeSlice(final PlanetModel planetModel, final double longitude) {
+    super(planetModel);
+    // Argument checking
+    if (longitude < -Math.PI || longitude > Math.PI)
+      throw new IllegalArgumentException("Longitude out of range");
+    this.longitude = longitude;
+
+    final double sinLongitude = Math.sin(longitude);
+    final double cosLongitude = Math.cos(longitude);
+
+    this.plane = new Plane(cosLongitude, sinLongitude);
+    // We need a bounding plane too, which is perpendicular to the longitude plane and sided so that the point (0.0, longitude) is inside.
+    this.interiorPoint = new GeoPoint(planetModel, 0.0, sinLongitude, 1.0, cosLongitude);
+    this.boundingPlane = new SidedPlane(interiorPoint, -sinLongitude, cosLongitude);
+    this.edgePoints = new GeoPoint[]{interiorPoint};
+    this.planePoints = new GeoPoint[]{planetModel.NORTH_POLE, planetModel.SOUTH_POLE};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    // Figuring out when we escalate to a special case requires some prefiguring
+    double newLeftLon = longitude - angle;
+    double newRightLon = longitude + angle;
+    double currentLonSpan = 2.0 * angle;
+    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
+      newLeftLon = -Math.PI;
+      newRightLon = Math.PI;
+    }
+    return GeoBBoxFactory.makeGeoBBox(planetModel, Math.PI * 0.5, -Math.PI * 0.5, newLeftLon, newRightLon);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return plane.evaluateIsZero(x, y, z) &&
+        boundingPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public double getRadius() {
+    return Math.PI * 0.5;
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    return interiorPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return p.intersects(planetModel, plane, notablePoints, planePoints, bounds, boundingPlane);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds
+      .addVerticalPlane(planetModel, longitude, plane, boundingPlane)
+      .addPoint(planetModel.NORTH_POLE).addPoint(planetModel.SOUTH_POLE);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    // Look for intersections.
+    if (path.intersects(plane, planePoints, boundingPlane))
+      return OVERLAPS;
+
+    if (path.isWithin(interiorPoint))
+      return CONTAINS;
+
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    final double distance = distanceStyle.computeDistance(planetModel, plane, x,y,z, boundingPlane);
+    
+    final double northDistance = distanceStyle.computeDistance(planetModel.NORTH_POLE, x,y,z);
+    final double southDistance = distanceStyle.computeDistance(planetModel.SOUTH_POLE, x,y,z);
+    
+    return Math.min(
+      distance,
+      Math.min(northDistance, southDistance));
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoDegenerateLongitudeSlice))
+      return false;
+    GeoDegenerateLongitudeSlice other = (GeoDegenerateLongitudeSlice) o;
+    return super.equals(other) && other.longitude == longitude;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    long temp = Double.doubleToLongBits(longitude);
+    result = result * 31 + (int) (temp ^ (temp >>> 32));
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoDegenerateLongitudeSlice: {planetmodel="+planetModel+", longitude=" + longitude + "(" + longitude * 180.0 / Math.PI + ")}";
+  }
+}
+  
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegeneratePoint.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegeneratePoint.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegeneratePoint.java
new file mode 100644
index 0000000..fcd2037
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegeneratePoint.java
@@ -0,0 +1,135 @@
+/*
+ * 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.spatial3d.geom;
+    
+/**
+ * This class represents a degenerate point bounding box.
+ * It is not a simple GeoPoint because we must have the latitude and longitude.
+ *
+ * @lucene.internal
+ */
+public class GeoDegeneratePoint extends GeoPoint implements GeoBBox, GeoCircle {
+  /** Current planet model, since we don't extend BasePlanetObject */
+  protected final PlanetModel planetModel;
+  /** Edge point is an area containing just this */
+  protected final GeoPoint[] edgePoints;
+
+  /** Constructor.
+   *@param planetModel is the planet model to use.
+   *@param lat is the latitude.
+   *@param lon is the longitude.
+   */
+  public GeoDegeneratePoint(final PlanetModel planetModel, final double lat, final double lon) {
+    super(planetModel, lat, lon);
+    this.planetModel = planetModel;
+    this.edgePoints = new GeoPoint[]{this};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    final double newTopLat = latitude + angle;
+    final double newBottomLat = latitude - angle;
+    final double newLeftLon = longitude - angle;
+    final double newRightLon = longitude + angle;
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane plane, final GeoPoint[] notablePoints, final Membership... bounds) {
+    // If not on the plane, no intersection
+    if (!plane.evaluateIsZero(this))
+      return false;
+
+    for (Membership m : bounds) {
+      if (!m.isWithin(this))
+        return false;
+    }
+    return true;
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    bounds.addPoint(this);
+  }
+
+  @Override
+  public double computeOutsideDistance(final DistanceStyle distanceStyle, final GeoPoint point) {
+    return distanceStyle.computeDistance(this, point);
+  }
+
+  @Override
+  public double computeOutsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    return distanceStyle.computeDistance(this, x,y,z);
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoDegeneratePoint))
+      return false;
+    GeoDegeneratePoint other = (GeoDegeneratePoint) o;
+    return super.equals(other) && other.latitude == latitude && other.longitude == longitude;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoDegeneratePoint: {planetmodel="+planetModel+", lat=" + latitude + "(" + latitude * 180.0 / Math.PI + "), lon=" + longitude + "(" + longitude * 180.0 / Math.PI + ")}";
+  }
+
+  @Override
+  public boolean isWithin(final Vector point) {
+    return isWithin(point.x, point.y, point.z);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return x == this.x && y == this.y && z == this.z;
+  }
+
+  @Override
+  public double getRadius() {
+    return 0.0;
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    return this;
+  }
+
+  @Override
+  public int getRelationship(final GeoShape shape) {
+    if (shape.isWithin(this)) {
+      //System.err.println("Degenerate point "+this+" is WITHIN shape "+shape);
+      return CONTAINS;
+    }
+
+    //System.err.println("Degenerate point "+this+" is NOT within shape "+shape);
+    return DISJOINT;
+  }
+
+  @Override
+  public double computeDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    if (isWithin(x,y,z))
+      return 0.0;
+    return Double.MAX_VALUE;
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateVerticalLine.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateVerticalLine.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateVerticalLine.java
new file mode 100644
index 0000000..dff53b4
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDegenerateVerticalLine.java
@@ -0,0 +1,205 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Degenerate bounding box limited on two sides (top lat, bottom lat).
+ *
+ * @lucene.internal
+ */
+public class GeoDegenerateVerticalLine extends GeoBaseBBox {
+  /** Top latitude of the vertical line */
+  protected final double topLat;
+  /** Bottom latitude of the vertical line */
+  protected final double bottomLat;
+  /** Longitude of the vertical line */
+  protected final double longitude;
+
+  /** Point at the upper end of the vertical line */
+  protected final GeoPoint UHC;
+  /** Point at the lower end of the vertical line */
+  protected final GeoPoint LHC;
+
+  /** Top end cutoff plane */
+  protected final SidedPlane topPlane;
+  /** Bottom end cutoff plane */
+  protected final SidedPlane bottomPlane;
+  /** Back-side cutoff plane */
+  protected final SidedPlane boundingPlane;
+  /** The vertical line plane */
+  protected final Plane plane;
+  /** Notable points for the line (end points) */
+  protected final GeoPoint[] planePoints;
+  /** A computed center point for the line */
+  protected final GeoPoint centerPoint;
+  /** A point that's on the line */
+  protected final GeoPoint[] edgePoints;
+
+  /**
+   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, longitude: {@code -PI -> PI}
+   */
+  public GeoDegenerateVerticalLine(final PlanetModel planetModel, final double topLat, final double bottomLat, final double longitude) {
+    super(planetModel);
+    // Argument checking
+    if (topLat > Math.PI * 0.5 || topLat < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Top latitude out of range");
+    if (bottomLat > Math.PI * 0.5 || bottomLat < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Bottom latitude out of range");
+    if (topLat < bottomLat)
+      throw new IllegalArgumentException("Top latitude less than bottom latitude");
+    if (longitude < -Math.PI || longitude > Math.PI)
+      throw new IllegalArgumentException("Longitude out of range");
+
+    this.topLat = topLat;
+    this.bottomLat = bottomLat;
+    this.longitude = longitude;
+
+    final double sinTopLat = Math.sin(topLat);
+    final double cosTopLat = Math.cos(topLat);
+    final double sinBottomLat = Math.sin(bottomLat);
+    final double cosBottomLat = Math.cos(bottomLat);
+    final double sinLongitude = Math.sin(longitude);
+    final double cosLongitude = Math.cos(longitude);
+
+    // Now build the two points
+    this.UHC = new GeoPoint(planetModel, sinTopLat, sinLongitude, cosTopLat, cosLongitude, topLat, longitude);
+    this.LHC = new GeoPoint(planetModel, sinBottomLat, sinLongitude, cosBottomLat, cosLongitude, bottomLat, longitude);
+
+    this.plane = new Plane(cosLongitude, sinLongitude);
+
+    final double middleLat = (topLat + bottomLat) * 0.5;
+    final double sinMiddleLat = Math.sin(middleLat);
+    final double cosMiddleLat = Math.cos(middleLat);
+
+    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinLongitude, cosMiddleLat, cosLongitude);
+
+    this.topPlane = new SidedPlane(centerPoint, planetModel, sinTopLat);
+    this.bottomPlane = new SidedPlane(centerPoint, planetModel, sinBottomLat);
+
+    this.boundingPlane = new SidedPlane(centerPoint, -sinLongitude, cosLongitude);
+
+    this.planePoints = new GeoPoint[]{UHC, LHC};
+
+    this.edgePoints = new GeoPoint[]{centerPoint};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    final double newTopLat = topLat + angle;
+    final double newBottomLat = bottomLat - angle;
+    double newLeftLon = longitude - angle;
+    double newRightLon = longitude + angle;
+    double currentLonSpan = 2.0 * angle;
+    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
+      newLeftLon = -Math.PI;
+      newRightLon = Math.PI;
+    }
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return plane.evaluateIsZero(x, y, z) &&
+        boundingPlane.isWithin(x, y, z) &&
+        topPlane.isWithin(x, y, z) &&
+        bottomPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public double getRadius() {
+    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
+    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
+    // the distance to the right or left edge from the center.
+    final double topAngle = centerPoint.arcDistance(UHC);
+    final double bottomAngle = centerPoint.arcDistance(LHC);
+    return Math.max(topAngle, bottomAngle);
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    return centerPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return p.intersects(planetModel, plane, notablePoints, planePoints, bounds, boundingPlane, topPlane, bottomPlane);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds.addVerticalPlane(planetModel, longitude, plane, boundingPlane, topPlane, bottomPlane)
+      .addPoint(UHC).addPoint(LHC);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    //System.err.println(this+" relationship to "+path);
+    if (path.intersects(plane, planePoints, boundingPlane, topPlane, bottomPlane)) {
+      //System.err.println(" overlaps");
+      return OVERLAPS;
+    }
+
+    if (path.isWithin(centerPoint)) {
+      //System.err.println(" contains");
+      return CONTAINS;
+    }
+
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    final double distance = distanceStyle.computeDistance(planetModel, plane, x,y,z, topPlane, bottomPlane, boundingPlane);
+    
+    final double UHCDistance = distanceStyle.computeDistance(UHC, x,y,z);
+    final double LHCDistance = distanceStyle.computeDistance(LHC, x,y,z);
+    
+    return Math.min(
+      distance,
+      Math.min(UHCDistance, LHCDistance));
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoDegenerateVerticalLine))
+      return false;
+    GeoDegenerateVerticalLine other = (GeoDegenerateVerticalLine) o;
+    return super.equals(other) && other.UHC.equals(UHC) && other.LHC.equals(LHC);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + UHC.hashCode();
+    result = 31 * result + LHC.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoDegenerateVerticalLine: {longitude=" + longitude + "(" + longitude * 180.0 / Math.PI + "), toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + "), bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + ")}";
+  }
+}
+  
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDistance.java
new file mode 100755
index 0000000..d41dd51
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDistance.java
@@ -0,0 +1,59 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * An implementer of this interface is capable of computing the described "distance" values,
+ * which are meant to provide both actual distance values, as well as
+ * distance estimates that can be computed more cheaply.
+ *
+ * @lucene.experimental
+ */
+public interface GeoDistance extends Membership {
+  
+  // The following methods compute distances from the shape to a point
+  // expected to be INSIDE the shape.  Typically a value of Double.MAX_VALUE
+  // is returned for points that happen to be outside the shape.
+
+  /**
+   * Compute this shape's <em>internal</em> "distance" to the GeoPoint.
+   * Implementations should clarify how this is computed when it's non-obvious.
+   * A return value of Double.MAX_VALUE should be returned for
+   * points outside of the shape.
+   *
+   * @param distanceStyle is the distance style.
+   * @param point is the point to compute the distance to.
+   * @return the distance.
+   */
+  public default double computeDistance(final DistanceStyle distanceStyle, final GeoPoint point) {
+    return computeDistance(distanceStyle, point.x, point.y, point.z);
+  }
+
+  /**
+   * Compute this shape's <em>internal</em> "distance" to the GeoPoint.
+   * Implementations should clarify how this is computed when it's non-obvious.
+   * A return value of Double.MAX_VALUE should be returned for
+   * points outside of the shape.
+   *
+   * @param x is the point's unit x coordinate (using U.S. convention).
+   * @param y is the point's unit y coordinate (using U.S. convention).
+   * @param z is the point's unit z coordinate (using U.S. convention).
+   * @return the distance.
+   */
+  public double computeDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z);
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDistanceShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDistanceShape.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDistanceShape.java
new file mode 100755
index 0000000..e7b0348
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoDistanceShape.java
@@ -0,0 +1,27 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Distance shapes have capabilities of both geohashing and distance
+ * computation (which also includes point membership determination).
+ *
+ * @lucene.experimental
+ */
+public interface GeoDistanceShape extends GeoMembershipShape, GeoDistance {
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoLatitudeZone.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoLatitudeZone.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoLatitudeZone.java
new file mode 100755
index 0000000..912ca32
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoLatitudeZone.java
@@ -0,0 +1,198 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * This GeoBBox represents an area rectangle limited only in latitude.
+ *
+ * @lucene.internal
+ */
+public class GeoLatitudeZone extends GeoBaseBBox {
+  /** The top latitude of the zone */
+  protected final double topLat;
+  /** The bottom latitude of the zone */
+  protected final double bottomLat;
+  /** Cosine of the top lat */
+  protected final double cosTopLat;
+  /** Cosine of the bottom lat */
+  protected final double cosBottomLat;
+  /** The top plane */
+  protected final SidedPlane topPlane;
+  /** The bottom plane */
+  protected final SidedPlane bottomPlane;
+  /** An interior point */
+  protected final GeoPoint interiorPoint;
+  /** Notable points (none) */
+  protected final static GeoPoint[] planePoints = new GeoPoint[0];
+
+  // We need two additional points because a latitude zone's boundaries don't intersect.  This is a very
+  // special case that most GeoBBox's do not have.
+  
+  /** Top boundary point */
+  protected final GeoPoint topBoundaryPoint;
+  /** Bottom boundary point */
+  protected final GeoPoint bottomBoundaryPoint;
+  /** A point on each distinct edge */
+  protected final GeoPoint[] edgePoints;
+
+  /** Constructor.
+   *@param planetModel is the planet model to use.
+   *@param topLat is the top latitude.
+   *@param bottomLat is the bottom latitude.
+   */
+  public GeoLatitudeZone(final PlanetModel planetModel, final double topLat, final double bottomLat) {
+    super(planetModel);
+    this.topLat = topLat;
+    this.bottomLat = bottomLat;
+
+    final double sinTopLat = Math.sin(topLat);
+    final double sinBottomLat = Math.sin(bottomLat);
+    this.cosTopLat = Math.cos(topLat);
+    this.cosBottomLat = Math.cos(bottomLat);
+
+    // Compute an interior point.  Pick one whose lat is between top and bottom.
+    final double middleLat = (topLat + bottomLat) * 0.5;
+    final double sinMiddleLat = Math.sin(middleLat);
+    this.interiorPoint = new GeoPoint(planetModel, sinMiddleLat, 0.0, Math.sqrt(1.0 - sinMiddleLat * sinMiddleLat), 1.0);
+    this.topBoundaryPoint = new GeoPoint(planetModel, sinTopLat, 0.0, Math.sqrt(1.0 - sinTopLat * sinTopLat), 1.0);
+    this.bottomBoundaryPoint = new GeoPoint(planetModel, sinBottomLat, 0.0, Math.sqrt(1.0 - sinBottomLat * sinBottomLat), 1.0);
+
+    this.topPlane = new SidedPlane(interiorPoint, planetModel, sinTopLat);
+    this.bottomPlane = new SidedPlane(interiorPoint, planetModel, sinBottomLat);
+
+    this.edgePoints = new GeoPoint[]{topBoundaryPoint, bottomBoundaryPoint};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    final double newTopLat = topLat + angle;
+    final double newBottomLat = bottomLat - angle;
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, -Math.PI, Math.PI);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return topPlane.isWithin(x, y, z) &&
+        bottomPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public double getRadius() {
+    // This is a bit tricky.  I guess we should interpret this as meaning the angle of a circle that
+    // would contain all the bounding box points, when starting in the "center".
+    if (topLat > 0.0 && bottomLat < 0.0)
+      return Math.PI;
+    double maxCosLat = cosTopLat;
+    if (maxCosLat < cosBottomLat)
+      maxCosLat = cosBottomLat;
+    return maxCosLat * Math.PI;
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    // This is totally arbitrary and only a cartesian could agree with it.
+    return interiorPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return p.intersects(planetModel, topPlane, notablePoints, planePoints, bounds, bottomPlane) ||
+        p.intersects(planetModel, bottomPlane, notablePoints, planePoints, bounds, topPlane);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds.noLongitudeBound()
+      .addHorizontalPlane(planetModel, topLat, topPlane)
+      .addHorizontalPlane(planetModel, bottomLat, bottomPlane);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    final int insideRectangle = isShapeInsideBBox(path);
+    if (insideRectangle == SOME_INSIDE)
+      return OVERLAPS;
+
+    final boolean topBoundaryInsideShape = path.isWithin(topBoundaryPoint);
+    final boolean bottomBoundaryInsideShape = path.isWithin(bottomBoundaryPoint);
+
+    if (topBoundaryInsideShape && !bottomBoundaryInsideShape ||
+        !topBoundaryInsideShape && bottomBoundaryInsideShape)
+      return OVERLAPS;
+
+    final boolean insideShape = topBoundaryInsideShape && bottomBoundaryInsideShape;
+
+    if (insideRectangle == ALL_INSIDE && insideShape)
+      return OVERLAPS;
+
+    // Second, the shortcut of seeing whether endpoints are in/out is not going to
+    // work with no area endpoints.  So we rely entirely on intersections.
+
+    if (path.intersects(topPlane, planePoints, bottomPlane) ||
+        path.intersects(bottomPlane, planePoints, topPlane))
+      return OVERLAPS;
+
+    // There is another case for latitude zones only.  This is when the boundaries of the shape all fit
+    // within the zone, but the shape includes areas outside the zone crossing a pole.
+    // In this case, the above "overlaps" check is insufficient.  We also need to check a point on either boundary
+    // whether it is within the shape.  If both such points are within, then CONTAINS is the right answer.  If
+    // one such point is within, then OVERLAPS is the right answer.
+
+    if (insideShape)
+      return CONTAINS;
+
+    if (insideRectangle == ALL_INSIDE)
+      return WITHIN;
+
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    final double topDistance = distanceStyle.computeDistance(planetModel, topPlane, x,y,z, bottomPlane);
+    final double bottomDistance = distanceStyle.computeDistance(planetModel, bottomPlane, x,y,z, topPlane);
+
+    return Math.min(topDistance, bottomDistance);
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoLatitudeZone))
+      return false;
+    GeoLatitudeZone other = (GeoLatitudeZone) o;
+    return super.equals(other) && other.topBoundaryPoint.equals(topBoundaryPoint) && other.bottomBoundaryPoint.equals(bottomBoundaryPoint);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + topBoundaryPoint.hashCode();
+    result = 31 * result + bottomBoundaryPoint.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoLatitudeZone: {planetmodel="+planetModel+", toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + "), bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + ")}";
+  }
+}


[23/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 3a31a8c)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoRectangle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoRectangle.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoRectangle.java
new file mode 100755
index 0000000..1420c11
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoRectangle.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.spatial3d.geom;
+
+/**
+ * Bounding box limited on four sides (top lat, bottom lat, left lon, right lon).
+ * The left-right maximum extent for this shape is PI; for anything larger, use
+ * GeoWideRectangle.
+ *
+ * @lucene.internal
+ */
+public class GeoRectangle extends GeoBaseBBox {
+  /** The top latitude of the rect */
+  protected final double topLat;
+  /** The bottom latitude of the rect */
+  protected final double bottomLat;
+  /** The left longitude of the rect */
+  protected final double leftLon;
+  /** The right longitude of the rect */
+  protected final double rightLon;
+  /** The cosine of a middle latitude */
+  protected final double cosMiddleLat;
+
+  /** The upper left hand corner point */
+  protected final GeoPoint ULHC;
+  /** The upper right hand corner point */
+  protected final GeoPoint URHC;
+  /** The lower right hand corner point */
+  protected final GeoPoint LRHC;
+  /** The lower left hand corner point */
+  protected final GeoPoint LLHC;
+
+  /** The top plane */
+  protected final SidedPlane topPlane;
+  /** The bottom plane */
+  protected final SidedPlane bottomPlane;
+  /** The left plane */
+  protected final SidedPlane leftPlane;
+  /** The right plane */
+  protected final SidedPlane rightPlane;
+
+  /** Notable points for the top plane */
+  protected final GeoPoint[] topPlanePoints;
+  /** Notable points for the bottom plane */
+  protected final GeoPoint[] bottomPlanePoints;
+  /** Notable points for the left plane */
+  protected final GeoPoint[] leftPlanePoints;
+  /** Notable points for the right plane */
+  protected final GeoPoint[] rightPlanePoints;
+
+  /** Center point */
+  protected final GeoPoint centerPoint;
+
+  /** Edge point for this rectangle */
+  protected final GeoPoint[] edgePoints;
+
+  /**
+   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
+   *@param planetModel is the planet model.
+   *@param topLat is the top latitude.
+   *@param bottomLat is the bottom latitude.
+   *@param leftLon is the left longitude.
+   *@param rightLon is the right longitude.
+   */
+  public GeoRectangle(final PlanetModel planetModel, final double topLat, final double bottomLat, final double leftLon, double rightLon) {
+    super(planetModel);
+    // Argument checking
+    if (topLat > Math.PI * 0.5 || topLat < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Top latitude out of range");
+    if (bottomLat > Math.PI * 0.5 || bottomLat < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Bottom latitude out of range");
+    if (topLat < bottomLat)
+      throw new IllegalArgumentException("Top latitude less than bottom latitude");
+    if (leftLon < -Math.PI || leftLon > Math.PI)
+      throw new IllegalArgumentException("Left longitude out of range");
+    if (rightLon < -Math.PI || rightLon > Math.PI)
+      throw new IllegalArgumentException("Right longitude out of range");
+    double extent = rightLon - leftLon;
+    if (extent < 0.0) {
+      extent += 2.0 * Math.PI;
+    }
+    if (extent > Math.PI)
+      throw new IllegalArgumentException("Width of rectangle too great");
+
+    this.topLat = topLat;
+    this.bottomLat = bottomLat;
+    this.leftLon = leftLon;
+    this.rightLon = rightLon;
+
+    final double sinTopLat = Math.sin(topLat);
+    final double cosTopLat = Math.cos(topLat);
+    final double sinBottomLat = Math.sin(bottomLat);
+    final double cosBottomLat = Math.cos(bottomLat);
+    final double sinLeftLon = Math.sin(leftLon);
+    final double cosLeftLon = Math.cos(leftLon);
+    final double sinRightLon = Math.sin(rightLon);
+    final double cosRightLon = Math.cos(rightLon);
+
+    // Now build the four points
+    this.ULHC = new GeoPoint(planetModel, sinTopLat, sinLeftLon, cosTopLat, cosLeftLon, topLat, leftLon);
+    this.URHC = new GeoPoint(planetModel, sinTopLat, sinRightLon, cosTopLat, cosRightLon, topLat, rightLon);
+    this.LRHC = new GeoPoint(planetModel, sinBottomLat, sinRightLon, cosBottomLat, cosRightLon, bottomLat, rightLon);
+    this.LLHC = new GeoPoint(planetModel, sinBottomLat, sinLeftLon, cosBottomLat, cosLeftLon, bottomLat, leftLon);
+
+    final double middleLat = (topLat + bottomLat) * 0.5;
+    final double sinMiddleLat = Math.sin(middleLat);
+    this.cosMiddleLat = Math.cos(middleLat);
+    // Normalize
+    while (leftLon > rightLon) {
+      rightLon += Math.PI * 2.0;
+    }
+    final double middleLon = (leftLon + rightLon) * 0.5;
+    final double sinMiddleLon = Math.sin(middleLon);
+    final double cosMiddleLon = Math.cos(middleLon);
+
+    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinMiddleLon, cosMiddleLat, cosMiddleLon);
+
+    this.topPlane = new SidedPlane(centerPoint, planetModel, sinTopLat);
+    this.bottomPlane = new SidedPlane(centerPoint, planetModel, sinBottomLat);
+    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
+    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
+
+    this.topPlanePoints = new GeoPoint[]{ULHC, URHC};
+    this.bottomPlanePoints = new GeoPoint[]{LLHC, LRHC};
+    this.leftPlanePoints = new GeoPoint[]{ULHC, LLHC};
+    this.rightPlanePoints = new GeoPoint[]{URHC, LRHC};
+
+    this.edgePoints = new GeoPoint[]{ULHC};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    final double newTopLat = topLat + angle;
+    final double newBottomLat = bottomLat - angle;
+    // Figuring out when we escalate to a special case requires some prefiguring
+    double currentLonSpan = rightLon - leftLon;
+    if (currentLonSpan < 0.0)
+      currentLonSpan += Math.PI * 2.0;
+    double newLeftLon = leftLon - angle;
+    double newRightLon = rightLon + angle;
+    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
+      newLeftLon = -Math.PI;
+      newRightLon = Math.PI;
+    }
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return topPlane.isWithin(x, y, z) &&
+        bottomPlane.isWithin(x, y, z) &&
+        leftPlane.isWithin(x, y, z) &&
+        rightPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public double getRadius() {
+    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
+    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
+    // the distance to the right or left edge from the center.
+    final double centerAngle = (rightLon - (rightLon + leftLon) * 0.5) * cosMiddleLat;
+    final double topAngle = centerPoint.arcDistance(URHC);
+    final double bottomAngle = centerPoint.arcDistance(LLHC);
+    return Math.max(centerAngle, Math.max(topAngle, bottomAngle));
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    return centerPoint;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return p.intersects(planetModel, topPlane, notablePoints, topPlanePoints, bounds, bottomPlane, leftPlane, rightPlane) ||
+        p.intersects(planetModel, bottomPlane, notablePoints, bottomPlanePoints, bounds, topPlane, leftPlane, rightPlane) ||
+        p.intersects(planetModel, leftPlane, notablePoints, leftPlanePoints, bounds, rightPlane, topPlane, bottomPlane) ||
+        p.intersects(planetModel, rightPlane, notablePoints, rightPlanePoints, bounds, leftPlane, topPlane, bottomPlane);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds.addHorizontalPlane(planetModel, topLat, topPlane, bottomPlane, leftPlane, rightPlane)
+      .addVerticalPlane(planetModel, rightLon, rightPlane, topPlane, bottomPlane, leftPlane)
+      .addHorizontalPlane(planetModel, bottomLat, bottomPlane, topPlane, leftPlane, rightPlane)
+      .addVerticalPlane(planetModel, leftLon, leftPlane, topPlane, bottomPlane, rightPlane)
+      .addPoint(ULHC).addPoint(URHC).addPoint(LLHC).addPoint(LRHC);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    //System.err.println(this+" getrelationship with "+path);
+    final int insideRectangle = isShapeInsideBBox(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some inside");
+      return OVERLAPS;
+    }
+
+    final boolean insideShape = path.isWithin(ULHC);
+
+    if (insideRectangle == ALL_INSIDE && insideShape) {
+      //System.err.println(" inside of each other");
+      return OVERLAPS;
+    }
+
+    if (path.intersects(topPlane, topPlanePoints, bottomPlane, leftPlane, rightPlane) ||
+        path.intersects(bottomPlane, bottomPlanePoints, topPlane, leftPlane, rightPlane) ||
+        path.intersects(leftPlane, leftPlanePoints, topPlane, bottomPlane, rightPlane) ||
+        path.intersects(rightPlane, rightPlanePoints, leftPlane, topPlane, bottomPlane)) {
+      //System.err.println(" edges intersect");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      //System.err.println(" shape inside rectangle");
+      return WITHIN;
+    }
+
+    if (insideShape) {
+      //System.err.println(" shape contains rectangle");
+      return CONTAINS;
+    }
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    final double topDistance = distanceStyle.computeDistance(planetModel, topPlane, x,y,z, bottomPlane, leftPlane, rightPlane);
+    final double bottomDistance = distanceStyle.computeDistance(planetModel, bottomPlane, x,y,z, topPlane, leftPlane, rightPlane);
+    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, rightPlane, topPlane, bottomPlane);
+    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, leftPlane, topPlane, bottomPlane);
+    
+    final double ULHCDistance = distanceStyle.computeDistance(ULHC, x,y,z);
+    final double URHCDistance = distanceStyle.computeDistance(URHC, x,y,z);
+    final double LRHCDistance = distanceStyle.computeDistance(LRHC, x,y,z);
+    final double LLHCDistance = distanceStyle.computeDistance(LLHC, x,y,z);
+    
+    return Math.min(
+      Math.min(
+        Math.min(topDistance, bottomDistance),
+        Math.min(leftDistance, rightDistance)),
+      Math.min(
+        Math.min(ULHCDistance, URHCDistance),
+        Math.min(LRHCDistance, LLHCDistance)));
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoRectangle))
+      return false;
+    GeoRectangle other = (GeoRectangle) o;
+    return super.equals(other) && other.ULHC.equals(ULHC) && other.LRHC.equals(LRHC);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result  + ULHC.hashCode();
+    result = 31 * result  + LRHC.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoRectangle: {planetmodel="+planetModel+", toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + "), bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
+  }
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoShape.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoShape.java
new file mode 100755
index 0000000..a2d3947
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoShape.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.spatial3d.geom;
+
+/**
+ * Generic shape.  This describes methods that help GeoAreas figure out
+ * how they interact with a shape, for the purposes of coming up with a
+ * set of geo hash values.
+ *
+ * @lucene.experimental
+ */
+public interface GeoShape extends Membership {
+
+  /**
+   * Return a sample point that is on the outside edge/boundary of the shape.
+   *
+   * @return samples of all edge points from distinct edge sections.  Typically one point
+   * is returned, but zero or two are also possible.
+   */
+  public GeoPoint[] getEdgePoints();
+
+  /**
+   * Assess whether a plane, within the provided bounds, intersects
+   * with the shape.  Note well that this method is allowed to return "true"
+   * if there are internal edges of a composite shape which intersect the plane.
+   * Doing this can cause getRelationship() for most GeoBBox shapes to return
+   * OVERLAPS rather than the more correct CONTAINS, but that cannot be
+   * helped for some complex shapes that are built out of overlapping parts.
+   *
+   * @param plane         is the plane to assess for intersection with the shape's edges or
+   *                      bounding curves.
+   * @param notablePoints represents the intersections of the plane with the supplied
+   *                      bounds.  These are used to disambiguate when two planes are identical and it needs
+   *                      to be determined whether any points exist that fulfill all the bounds.
+   * @param bounds        are a set of bounds that define an area that an
+   *                      intersection must be within in order to qualify (provided by a GeoArea).
+   * @return true if there's such an intersection, false if not.
+   */
+  public boolean intersects(final Plane plane, final GeoPoint[] notablePoints, final Membership... bounds);
+
+  /**
+   * Compute bounds for the shape.
+   *
+   * @param bounds is the input bounds object.
+   *             The input object will be modified.
+   */
+  public void getBounds(final Bounds bounds);
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoSizeable.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoSizeable.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoSizeable.java
new file mode 100755
index 0000000..3c7e2ef
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoSizeable.java
@@ -0,0 +1,40 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Some shapes can compute radii of a geocircle in which they are inscribed.
+ *
+ * @lucene.experimental
+ */
+public interface GeoSizeable {
+  /**
+   * Returns the radius of a circle into which the GeoSizeable area can
+   * be inscribed.
+   *
+   * @return the radius.
+   */
+  public double getRadius();
+
+  /**
+   * Returns the center of a circle into which the area will be inscribed.
+   *
+   * @return the center.
+   */
+  public GeoPoint getCenter();
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoSouthLatitudeZone.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoSouthLatitudeZone.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoSouthLatitudeZone.java
new file mode 100644
index 0000000..a1d8967
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoSouthLatitudeZone.java
@@ -0,0 +1,168 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * This GeoBBox represents an area rectangle limited only in north latitude.
+ *
+ * @lucene.internal
+ */
+public class GeoSouthLatitudeZone extends GeoBaseBBox {
+  /** The top latitude of the zone */
+  protected final double topLat;
+  /** The cosine of the top latitude of the zone */
+  protected final double cosTopLat;
+  /** The top plane of the zone */
+  protected final SidedPlane topPlane;
+  /** An interior point of the zone */
+  protected final GeoPoint interiorPoint;
+  /** Notable points for the plane (none) */
+  protected final static GeoPoint[] planePoints = new GeoPoint[0];
+  /** A point on the top boundary */
+  protected final GeoPoint topBoundaryPoint;
+  /** Edge points; a reference to the topBoundaryPoint */
+  protected final GeoPoint[] edgePoints;
+
+  /** Constructor.
+   *@param planetModel is the planet model.
+   *@param topLat is the top latitude of the zone.
+   */
+  public GeoSouthLatitudeZone(final PlanetModel planetModel, final double topLat) {
+    super(planetModel);
+    this.topLat = topLat;
+
+    final double sinTopLat = Math.sin(topLat);
+    this.cosTopLat = Math.cos(topLat);
+
+    // Compute an interior point.  Pick one whose lat is between top and bottom.
+    final double middleLat = (topLat - Math.PI * 0.5) * 0.5;
+    final double sinMiddleLat = Math.sin(middleLat);
+    this.interiorPoint = new GeoPoint(planetModel, sinMiddleLat, 0.0, Math.sqrt(1.0 - sinMiddleLat * sinMiddleLat), 1.0);
+    this.topBoundaryPoint = new GeoPoint(planetModel, sinTopLat, 0.0, Math.sqrt(1.0 - sinTopLat * sinTopLat), 1.0);
+
+    this.topPlane = new SidedPlane(interiorPoint, planetModel, sinTopLat);
+
+    this.edgePoints = new GeoPoint[]{topBoundaryPoint};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    final double newTopLat = topLat + angle;
+    final double newBottomLat = -Math.PI * 0.5;
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, -Math.PI, Math.PI);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return topPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public double getRadius() {
+    // This is a bit tricky.  I guess we should interpret this as meaning the angle of a circle that
+    // would contain all the bounding box points, when starting in the "center".
+    if (topLat > 0.0)
+      return Math.PI;
+    double maxCosLat = cosTopLat;
+    return maxCosLat * Math.PI;
+  }
+
+  /**
+   * Returns the center of a circle into which the area will be inscribed.
+   *
+   * @return the center.
+   */
+  @Override
+  public GeoPoint getCenter() {
+    return interiorPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return p.intersects(planetModel, topPlane, notablePoints, planePoints, bounds);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds
+      .addHorizontalPlane(planetModel, topLat, topPlane);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    final int insideRectangle = isShapeInsideBBox(path);
+    if (insideRectangle == SOME_INSIDE)
+      return OVERLAPS;
+
+    final boolean insideShape = path.isWithin(topBoundaryPoint);
+
+    if (insideRectangle == ALL_INSIDE && insideShape)
+      return OVERLAPS;
+
+    // Second, the shortcut of seeing whether endpoints are in/out is not going to
+    // work with no area endpoints.  So we rely entirely on intersections.
+
+    if (path.intersects(topPlane, planePoints))
+      return OVERLAPS;
+
+    // There is another case for latitude zones only.  This is when the boundaries of the shape all fit
+    // within the zone, but the shape includes areas outside the zone crossing a pole.
+    // In this case, the above "overlaps" check is insufficient.  We also need to check a point on either boundary
+    // whether it is within the shape.  If both such points are within, then CONTAINS is the right answer.  If
+    // one such point is within, then OVERLAPS is the right answer.
+
+    if (insideShape)
+      return CONTAINS;
+
+    if (insideRectangle == ALL_INSIDE)
+      return WITHIN;
+
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    return distanceStyle.computeDistance(planetModel, topPlane, x,y,z);
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoSouthLatitudeZone))
+      return false;
+    GeoSouthLatitudeZone other = (GeoSouthLatitudeZone) o;
+    return super.equals(other) && other.topBoundaryPoint.equals(topBoundaryPoint);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + topBoundaryPoint.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoSouthLatitudeZone: {planetmodel="+planetModel+", toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + ")}";
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoSouthRectangle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoSouthRectangle.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoSouthRectangle.java
new file mode 100644
index 0000000..806535e
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoSouthRectangle.java
@@ -0,0 +1,259 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Bounding box limited on three sides (top lat, left lon, right lon).  The
+ * other corner is the south pole.
+ * The left-right maximum extent for this shape is PI; for anything larger, use
+ * {@link GeoWideSouthRectangle}.
+ *
+ * @lucene.internal
+ */
+public class GeoSouthRectangle extends GeoBaseBBox {
+  /** The top latitude of the rect */
+  protected final double topLat;
+  /** The left longitude of the rect */
+  protected final double leftLon;
+  /** The right longitude of the rect */
+  protected final double rightLon;
+  /** The cosine of a middle latitude */
+  protected final double cosMiddleLat;
+  /** The upper left hand corner of the rectangle */
+  protected final GeoPoint ULHC;
+  /** The upper right hand corner of the rectangle */
+  protected final GeoPoint URHC;
+
+  /** The top plane */
+  protected final SidedPlane topPlane;
+  /** The left plane */
+  protected final SidedPlane leftPlane;
+  /** The right plane */
+  protected final SidedPlane rightPlane;
+
+  /** Notable points for the top plane */
+  protected final GeoPoint[] topPlanePoints;
+  /** Notable points for the left plane */
+  protected final GeoPoint[] leftPlanePoints;
+  /** Notable points for the right plane */
+  protected final GeoPoint[] rightPlanePoints;
+
+  /** The center point */
+  protected final GeoPoint centerPoint;
+
+  /** A point on the edge */
+  protected final GeoPoint[] edgePoints;
+
+  /**
+   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
+   *@param planetModel is the planet model.
+   *@param topLat is the top latitude.
+   *@param leftLon is the left longitude.
+   *@param rightLon is the right longitude.
+   */
+  public GeoSouthRectangle(final PlanetModel planetModel, final double topLat, final double leftLon, double rightLon) {
+    super(planetModel);
+    // Argument checking
+    if (topLat > Math.PI * 0.5 || topLat < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Top latitude out of range");
+    if (leftLon < -Math.PI || leftLon > Math.PI)
+      throw new IllegalArgumentException("Left longitude out of range");
+    if (rightLon < -Math.PI || rightLon > Math.PI)
+      throw new IllegalArgumentException("Right longitude out of range");
+    double extent = rightLon - leftLon;
+    if (extent < 0.0) {
+      extent += 2.0 * Math.PI;
+    }
+    if (extent > Math.PI)
+      throw new IllegalArgumentException("Width of rectangle too great");
+
+    this.topLat = topLat;
+    this.leftLon = leftLon;
+    this.rightLon = rightLon;
+
+    final double sinTopLat = Math.sin(topLat);
+    final double cosTopLat = Math.cos(topLat);
+    final double sinLeftLon = Math.sin(leftLon);
+    final double cosLeftLon = Math.cos(leftLon);
+    final double sinRightLon = Math.sin(rightLon);
+    final double cosRightLon = Math.cos(rightLon);
+
+    // Now build the four points
+    this.ULHC = new GeoPoint(planetModel, sinTopLat, sinLeftLon, cosTopLat, cosLeftLon, topLat, leftLon);
+    this.URHC = new GeoPoint(planetModel, sinTopLat, sinRightLon, cosTopLat, cosRightLon, topLat, rightLon);
+
+    final double middleLat = (topLat - Math.PI * 0.5) * 0.5;
+    final double sinMiddleLat = Math.sin(middleLat);
+    this.cosMiddleLat = Math.cos(middleLat);
+    // Normalize
+    while (leftLon > rightLon) {
+      rightLon += Math.PI * 2.0;
+    }
+    final double middleLon = (leftLon + rightLon) * 0.5;
+    final double sinMiddleLon = Math.sin(middleLon);
+    final double cosMiddleLon = Math.cos(middleLon);
+
+    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinMiddleLon, cosMiddleLat, cosMiddleLon);
+
+    this.topPlane = new SidedPlane(centerPoint, planetModel, sinTopLat);
+    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
+    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
+
+    this.topPlanePoints = new GeoPoint[]{ULHC, URHC};
+    this.leftPlanePoints = new GeoPoint[]{ULHC, planetModel.SOUTH_POLE};
+    this.rightPlanePoints = new GeoPoint[]{URHC, planetModel.SOUTH_POLE};
+    
+    this.edgePoints = new GeoPoint[]{planetModel.SOUTH_POLE};
+
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    final double newTopLat = topLat + angle;
+    final double newBottomLat = -Math.PI * 0.5;
+    // Figuring out when we escalate to a special case requires some prefiguring
+    double currentLonSpan = rightLon - leftLon;
+    if (currentLonSpan < 0.0)
+      currentLonSpan += Math.PI * 2.0;
+    double newLeftLon = leftLon - angle;
+    double newRightLon = rightLon + angle;
+    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
+      newLeftLon = -Math.PI;
+      newRightLon = Math.PI;
+    }
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return topPlane.isWithin(x, y, z) &&
+        leftPlane.isWithin(x, y, z) &&
+        rightPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public double getRadius() {
+    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
+    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
+    // the distance to the right or left edge from the center.
+    final double centerAngle = (rightLon - (rightLon + leftLon) * 0.5) * cosMiddleLat;
+    final double topAngle = centerPoint.arcDistance(URHC);
+    return Math.max(centerAngle, topAngle);
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    return centerPoint;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return p.intersects(planetModel, topPlane, notablePoints, topPlanePoints, bounds, leftPlane, rightPlane) ||
+        p.intersects(planetModel, leftPlane, notablePoints, leftPlanePoints, bounds, rightPlane, topPlane) ||
+        p.intersects(planetModel, rightPlane, notablePoints, rightPlanePoints, bounds, leftPlane, topPlane);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds
+      .addHorizontalPlane(planetModel, topLat, topPlane, leftPlane, rightPlane)
+      .addVerticalPlane(planetModel, leftLon, leftPlane, topPlane, rightPlane)
+      .addVerticalPlane(planetModel, rightLon, rightPlane, topPlane, leftPlane)
+      .addPoint(URHC).addPoint(ULHC).addPoint(planetModel.SOUTH_POLE);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    //System.err.println(this+" getrelationship with "+path);
+    final int insideRectangle = isShapeInsideBBox(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some inside");
+      return OVERLAPS;
+    }
+
+    final boolean insideShape = path.isWithin(planetModel.SOUTH_POLE);
+
+    if (insideRectangle == ALL_INSIDE && insideShape) {
+      //System.err.println(" inside of each other");
+      return OVERLAPS;
+    }
+
+    if (path.intersects(topPlane, topPlanePoints, leftPlane, rightPlane) ||
+        path.intersects(leftPlane, leftPlanePoints, topPlane, rightPlane) ||
+        path.intersects(rightPlane, rightPlanePoints, leftPlane, topPlane)) {
+      //System.err.println(" edges intersect");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      //System.err.println(" shape inside rectangle");
+      return WITHIN;
+    }
+
+    if (insideShape) {
+      //System.err.println(" shape contains rectangle");
+      return CONTAINS;
+    }
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    final double topDistance = distanceStyle.computeDistance(planetModel, topPlane, x,y,z, leftPlane, rightPlane);
+    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, rightPlane, topPlane);
+    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, leftPlane, topPlane);
+    
+    final double ULHCDistance = distanceStyle.computeDistance(ULHC, x,y,z);
+    final double URHCDistance = distanceStyle.computeDistance(URHC, x,y,z);
+    
+    return Math.min(
+      Math.min(
+        topDistance,
+        Math.min(leftDistance, rightDistance)),
+      Math.min(ULHCDistance, URHCDistance));
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoSouthRectangle))
+      return false;
+    GeoSouthRectangle other = (GeoSouthRectangle) o;
+    return super.equals(other) && other.ULHC.equals(ULHC) && other.URHC.equals(URHC);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + ULHC.hashCode();
+    result = 31 * result + URHC.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoSouthRectangle: {planetmodel="+planetModel+", toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
+  }
+}
+  
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoStandardCircle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoStandardCircle.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoStandardCircle.java
new file mode 100755
index 0000000..bbf5046
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoStandardCircle.java
@@ -0,0 +1,168 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Circular area with a center and radius.
+ *
+ * @lucene.experimental
+ */
+public class GeoStandardCircle extends GeoBaseCircle {
+  /** Center of circle */
+  protected final GeoPoint center;
+  /** Cutoff angle of circle (not quite the same thing as radius) */
+  protected final double cutoffAngle;
+  /** The plane describing the circle (really an ellipse on a non-spherical world) */
+  protected final SidedPlane circlePlane;
+  /** A point that is on the world and on the circle plane */
+  protected final GeoPoint[] edgePoints;
+  /** Notable points for a circle -- there aren't any */
+  protected static final GeoPoint[] circlePoints = new GeoPoint[0];
+
+  /** Constructor.
+   *@param planetModel is the planet model.
+   *@param lat is the center latitude.
+   *@param lon is the center longitude.
+   *@param cutoffAngle is the cutoff angle for the circle.
+   */
+  public GeoStandardCircle(final PlanetModel planetModel, final double lat, final double lon, final double cutoffAngle) {
+    super(planetModel);
+    if (lat < -Math.PI * 0.5 || lat > Math.PI * 0.5)
+      throw new IllegalArgumentException("Latitude out of bounds");
+    if (lon < -Math.PI || lon > Math.PI)
+      throw new IllegalArgumentException("Longitude out of bounds");
+    if (cutoffAngle < 0.0 || cutoffAngle > Math.PI)
+      throw new IllegalArgumentException("Cutoff angle out of bounds");
+    if (cutoffAngle < Vector.MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("Cutoff angle cannot be effectively zero");
+    this.center = new GeoPoint(planetModel, lat, lon);
+    // In an ellipsoidal world, cutoff distances make no sense, unfortunately.  Only membership
+    // can be used to make in/out determination.
+    this.cutoffAngle = cutoffAngle;
+    // Compute two points on the circle, with the right angle from the center.  We'll use these
+    // to obtain the perpendicular plane to the circle.
+    double upperLat = lat + cutoffAngle;
+    double upperLon = lon;
+    if (upperLat > Math.PI * 0.5) {
+      upperLon += Math.PI;
+      if (upperLon > Math.PI)
+        upperLon -= 2.0 * Math.PI;
+      upperLat = Math.PI - upperLat;
+    }
+    double lowerLat = lat - cutoffAngle;
+    double lowerLon = lon;
+    if (lowerLat < -Math.PI * 0.5) {
+      lowerLon += Math.PI;
+      if (lowerLon > Math.PI)
+        lowerLon -= 2.0 * Math.PI;
+      lowerLat = -Math.PI - lowerLat;
+    }
+    final GeoPoint upperPoint = new GeoPoint(planetModel, upperLat, upperLon);
+    final GeoPoint lowerPoint = new GeoPoint(planetModel, lowerLat, lowerLon);
+    if (Math.abs(cutoffAngle - Math.PI) < Vector.MINIMUM_RESOLUTION) {
+      // Circle is the whole world
+      this.circlePlane = null;
+      this.edgePoints = new GeoPoint[0];
+    } else {
+      // Construct normal plane
+      final Plane normalPlane = Plane.constructNormalizedZPlane(upperPoint, lowerPoint, center);
+      // Construct a sided plane that goes through the two points and whose normal is in the normalPlane.
+      this.circlePlane = SidedPlane.constructNormalizedPerpendicularSidedPlane(center, normalPlane, upperPoint, lowerPoint);
+      if (circlePlane == null)
+        throw new IllegalArgumentException("Couldn't construct circle plane, probably too small?  Cutoff angle = "+cutoffAngle+"; upperPoint = "+upperPoint+"; lowerPoint = "+lowerPoint);
+      final GeoPoint recomputedIntersectionPoint = circlePlane.getSampleIntersectionPoint(planetModel, normalPlane);
+      if (recomputedIntersectionPoint == null)
+        throw new IllegalArgumentException("Couldn't construct intersection point, probably circle too small?  Plane = "+circlePlane);
+      this.edgePoints = new GeoPoint[]{recomputedIntersectionPoint};
+    }
+  }
+
+  @Override
+  public double getRadius() {
+    return cutoffAngle;
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    return center;
+  }
+
+  @Override
+  protected double distance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    return distanceStyle.computeDistance(this.center, x, y, z);
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    return distanceStyle.computeDistance(planetModel, circlePlane, x, y, z);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    if (circlePlane == null) {
+      return true;
+    }
+    // Fastest way of determining membership
+    return circlePlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    if (circlePlane == null) {
+      return false;
+    }
+    return circlePlane.intersects(planetModel, p, notablePoints, circlePoints, bounds);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    if (circlePlane == null) {
+      // Entire world; should already be covered
+      return;
+    }
+    bounds.addPoint(center);
+    bounds.addPlane(planetModel, circlePlane);
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoStandardCircle))
+      return false;
+    GeoStandardCircle other = (GeoStandardCircle) o;
+    return super.equals(other) && other.center.equals(center) && other.cutoffAngle == cutoffAngle;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + center.hashCode();
+    long temp = Double.doubleToLongBits(cutoffAngle);
+    result = 31 * result + (int) (temp ^ (temp >>> 32));
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoStandardCircle: {planetmodel=" + planetModel+", center=" + center + ", radius=" + cutoffAngle + "(" + cutoffAngle * 180.0 / Math.PI + ")}";
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideDegenerateHorizontalLine.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideDegenerateHorizontalLine.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideDegenerateHorizontalLine.java
new file mode 100644
index 0000000..48a73af
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideDegenerateHorizontalLine.java
@@ -0,0 +1,238 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Degenerate bounding box wider than PI and limited on two sides (left lon, right lon).
+ *
+ * @lucene.internal
+ */
+public class GeoWideDegenerateHorizontalLine extends GeoBaseBBox {
+  /** The latitude of the line */
+  protected final double latitude;
+  /** The left longitude cutoff of the line */
+  protected final double leftLon;
+  /** The right longitude cutoff of the line */
+  protected final double rightLon;
+
+  /** The left end of the line */
+  protected final GeoPoint LHC;
+  /** The right end of the line */
+  protected final GeoPoint RHC;
+
+  /** The plane the line is in */
+  protected final Plane plane;
+  /** The left cutoff plane */
+  protected final SidedPlane leftPlane;
+  /** The right cutoff plane */
+  protected final SidedPlane rightPlane;
+
+  /** Notable points for the line */
+  protected final GeoPoint[] planePoints;
+
+  /** Center point for the line */
+  protected final GeoPoint centerPoint;
+
+  /** Left/right combination bound */
+  protected final EitherBound eitherBound;
+
+  /** A point on the line */
+  protected final GeoPoint[] edgePoints;
+
+  /**
+   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}.
+   * Horizontal angle must be greater than or equal to PI.
+   *@param planetModel is the planet model.
+   *@param latitude is the line latitude.
+   *@param leftLon is the left cutoff longitude.
+   *@param rightLon is the right cutoff longitude.
+   */
+  public GeoWideDegenerateHorizontalLine(final PlanetModel planetModel, final double latitude, final double leftLon, double rightLon) {
+    super(planetModel);
+    // Argument checking
+    if (latitude > Math.PI * 0.5 || latitude < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Latitude out of range");
+    if (leftLon < -Math.PI || leftLon > Math.PI)
+      throw new IllegalArgumentException("Left longitude out of range");
+    if (rightLon < -Math.PI || rightLon > Math.PI)
+      throw new IllegalArgumentException("Right longitude out of range");
+    double extent = rightLon - leftLon;
+    if (extent < 0.0) {
+      extent += 2.0 * Math.PI;
+    }
+    if (extent < Math.PI)
+      throw new IllegalArgumentException("Width of rectangle too small");
+
+    this.latitude = latitude;
+    this.leftLon = leftLon;
+    this.rightLon = rightLon;
+
+    final double sinLatitude = Math.sin(latitude);
+    final double cosLatitude = Math.cos(latitude);
+    final double sinLeftLon = Math.sin(leftLon);
+    final double cosLeftLon = Math.cos(leftLon);
+    final double sinRightLon = Math.sin(rightLon);
+    final double cosRightLon = Math.cos(rightLon);
+
+    // Now build the two points
+    this.LHC = new GeoPoint(planetModel, sinLatitude, sinLeftLon, cosLatitude, cosLeftLon, latitude, leftLon);
+    this.RHC = new GeoPoint(planetModel, sinLatitude, sinRightLon, cosLatitude, cosRightLon, latitude, rightLon);
+
+    this.plane = new Plane(planetModel, sinLatitude);
+
+    // Normalize
+    while (leftLon > rightLon) {
+      rightLon += Math.PI * 2.0;
+    }
+    double middleLon = (leftLon + rightLon) * 0.5;
+    double sinMiddleLon = Math.sin(middleLon);
+    double cosMiddleLon = Math.cos(middleLon);
+
+    this.centerPoint = new GeoPoint(planetModel, sinLatitude, sinMiddleLon, cosLatitude, cosMiddleLon);
+
+    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
+    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
+
+    this.planePoints = new GeoPoint[]{LHC, RHC};
+
+    this.eitherBound = new EitherBound();
+
+    this.edgePoints = new GeoPoint[]{centerPoint};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    final double newTopLat = latitude + angle;
+    final double newBottomLat = latitude - angle;
+    // Figuring out when we escalate to a special case requires some prefiguring
+    double currentLonSpan = rightLon - leftLon;
+    if (currentLonSpan < 0.0)
+      currentLonSpan += Math.PI * 2.0;
+    double newLeftLon = leftLon - angle;
+    double newRightLon = rightLon + angle;
+    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
+      newLeftLon = -Math.PI;
+      newRightLon = Math.PI;
+    }
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return plane.evaluateIsZero(x, y, z) &&
+        (leftPlane.isWithin(x, y, z) ||
+            rightPlane.isWithin(x, y, z));
+  }
+
+  @Override
+  public double getRadius() {
+    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
+    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
+    // the distance to the right or left edge from the center.
+    final double topAngle = centerPoint.arcDistance(RHC);
+    final double bottomAngle = centerPoint.arcDistance(LHC);
+    return Math.max(topAngle, bottomAngle);
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    return centerPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    // Right and left bounds are essentially independent hemispheres; crossing into the wrong part of one
+    // requires crossing into the right part of the other.  So intersection can ignore the left/right bounds.
+    return p.intersects(planetModel, plane, notablePoints, planePoints, bounds, eitherBound);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds.isWide()
+      .addHorizontalPlane(planetModel, latitude, plane, eitherBound)
+      .addPoint(LHC)
+      .addPoint(RHC);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    if (path.intersects(plane, planePoints, eitherBound)) {
+      return OVERLAPS;
+    }
+
+    if (path.isWithin(centerPoint)) {
+      return CONTAINS;
+    }
+
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    final double distance = distanceStyle.computeDistance(planetModel, plane, x,y,z, eitherBound);
+    
+    final double LHCDistance = distanceStyle.computeDistance(LHC, x,y,z);
+    final double RHCDistance = distanceStyle.computeDistance(RHC, x,y,z);
+    
+    return Math.min(
+      distance,
+      Math.min(LHCDistance, RHCDistance));
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoWideDegenerateHorizontalLine))
+      return false;
+    GeoWideDegenerateHorizontalLine other = (GeoWideDegenerateHorizontalLine) o;
+    return super.equals(other) && other.LHC.equals(LHC) && other.RHC.equals(RHC);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + LHC.hashCode();
+    result = 31 * result + RHC.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoWideDegenerateHorizontalLine: {planetmodel="+planetModel+", latitude=" + latitude + "(" + latitude * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightLon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
+  }
+
+  /** Membership implementation representing a wide cutoff (more than 180 degrees).
+   */
+  protected class EitherBound implements Membership {
+    /** Constructor.
+     */
+    public EitherBound() {
+    }
+
+    @Override
+    public boolean isWithin(final double x, final double y, final double z) {
+      return leftPlane.isWithin(x, y, z) || rightPlane.isWithin(x, y, z);
+    }
+  }
+}
+  
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideLongitudeSlice.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideLongitudeSlice.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideLongitudeSlice.java
new file mode 100755
index 0000000..1d61876
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideLongitudeSlice.java
@@ -0,0 +1,208 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Bounding box wider than PI but limited on left and right sides (
+ * left lon, right lon).
+ *
+ * @lucene.internal
+ */
+public class GeoWideLongitudeSlice extends GeoBaseBBox {
+  /** The left longitude */
+  protected final double leftLon;
+  /** The right longitude */
+  protected final double rightLon;
+
+  /** The left plane */
+  protected final SidedPlane leftPlane;
+  /** The right plane */
+  protected final SidedPlane rightPlane;
+
+  /** Notable points for the shape */
+  protected final GeoPoint[] planePoints;
+
+  /** Center point for the shape */
+  protected final GeoPoint centerPoint;
+
+  /** A point on the edge of the shape */
+  protected final GeoPoint[] edgePoints; 
+
+  /**
+   * Accepts only values in the following ranges: lon: {@code -PI -> PI}.
+   * Horizantal angle must be greater than or equal to PI.
+   *@param planetModel is the planet model.
+   *@param leftLon is the left longitude.
+   *@param rightLon is the right longitude.
+   */
+  public GeoWideLongitudeSlice(final PlanetModel planetModel, final double leftLon, double rightLon) {
+    super(planetModel);
+    // Argument checking
+    if (leftLon < -Math.PI || leftLon > Math.PI)
+      throw new IllegalArgumentException("Left longitude out of range");
+    if (rightLon < -Math.PI || rightLon > Math.PI)
+      throw new IllegalArgumentException("Right longitude out of range");
+    double extent = rightLon - leftLon;
+    if (extent < 0.0) {
+      extent += 2.0 * Math.PI;
+    }
+    if (extent < Math.PI)
+      throw new IllegalArgumentException("Width of rectangle too small");
+
+    this.leftLon = leftLon;
+    this.rightLon = rightLon;
+
+    final double sinLeftLon = Math.sin(leftLon);
+    final double cosLeftLon = Math.cos(leftLon);
+    final double sinRightLon = Math.sin(rightLon);
+    final double cosRightLon = Math.cos(rightLon);
+
+    // Normalize
+    while (leftLon > rightLon) {
+      rightLon += Math.PI * 2.0;
+    }
+    final double middleLon = (leftLon + rightLon) * 0.5;
+    this.centerPoint = new GeoPoint(planetModel, 0.0, middleLon);
+
+    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
+    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
+    
+    this.planePoints = new GeoPoint[]{planetModel.NORTH_POLE, planetModel.SOUTH_POLE};
+    this.edgePoints = new GeoPoint[]{planetModel.NORTH_POLE};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    // Figuring out when we escalate to a special case requires some prefiguring
+    double currentLonSpan = rightLon - leftLon;
+    if (currentLonSpan < 0.0)
+      currentLonSpan += Math.PI * 2.0;
+    double newLeftLon = leftLon - angle;
+    double newRightLon = rightLon + angle;
+    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
+      newLeftLon = -Math.PI;
+      newRightLon = Math.PI;
+    }
+    return GeoBBoxFactory.makeGeoBBox(planetModel, Math.PI * 0.5, -Math.PI * 0.5, newLeftLon, newRightLon);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return leftPlane.isWithin(x, y, z) ||
+        rightPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public double getRadius() {
+    // Compute the extent and divide by two
+    double extent = rightLon - leftLon;
+    if (extent < 0.0)
+      extent += Math.PI * 2.0;
+    return Math.max(Math.PI * 0.5, extent * 0.5);
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    return centerPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    // Right and left bounds are essentially independent hemispheres; crossing into the wrong part of one
+    // requires crossing into the right part of the other.  So intersection can ignore the left/right bounds.
+    return p.intersects(planetModel, leftPlane, notablePoints, planePoints, bounds) ||
+        p.intersects(planetModel, rightPlane, notablePoints, planePoints, bounds);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds.isWide()
+      .addVerticalPlane(planetModel, leftLon, leftPlane)
+      .addVerticalPlane(planetModel, rightLon, rightPlane)
+      .addPoint(planetModel.NORTH_POLE)
+      .addPoint(planetModel.SOUTH_POLE);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    final int insideRectangle = isShapeInsideBBox(path);
+    if (insideRectangle == SOME_INSIDE)
+      return OVERLAPS;
+
+    final boolean insideShape = path.isWithin(planetModel.NORTH_POLE);
+
+    if (insideRectangle == ALL_INSIDE && insideShape)
+      return OVERLAPS;
+
+    if (path.intersects(leftPlane, planePoints) ||
+        path.intersects(rightPlane, planePoints))
+      return OVERLAPS;
+
+    if (insideRectangle == ALL_INSIDE)
+      return WITHIN;
+
+    if (insideShape)
+      return CONTAINS;
+
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    // Because the rectangle exceeds 180 degrees, it is safe to compute the horizontally 
+    // unbounded distance to both the left and the right and only take the minimum of the two.
+    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z);
+    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z);
+    
+    final double northDistance = distanceStyle.computeDistance(planetModel.NORTH_POLE, x,y,z);
+    final double southDistance = distanceStyle.computeDistance(planetModel.SOUTH_POLE, x,y,z);
+    
+    return Math.min(
+      Math.min(leftDistance, rightDistance),
+      Math.min(northDistance, southDistance));
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoWideLongitudeSlice))
+      return false;
+    GeoWideLongitudeSlice other = (GeoWideLongitudeSlice) o;
+    return super.equals(other) && other.leftLon == leftLon && other.rightLon == rightLon;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    long temp = Double.doubleToLongBits(leftLon);
+    result = 31 * result + (int) (temp ^ (temp >>> 32));
+    temp = Double.doubleToLongBits(rightLon);
+    result = 31 * result + (int) (temp ^ (temp >>> 32));
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoWideLongitudeSlice: {planetmodel="+planetModel+", leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
+  }
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideNorthRectangle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideNorthRectangle.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideNorthRectangle.java
new file mode 100644
index 0000000..9f9dd49
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideNorthRectangle.java
@@ -0,0 +1,286 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Bounding box wider than PI but limited on three sides (
+ * bottom lat, left lon, right lon).
+ *
+ * @lucene.internal
+ */
+public class GeoWideNorthRectangle extends GeoBaseBBox {
+  /** Bottom latitude */
+  protected final double bottomLat;
+  /** Left longitude */
+  protected final double leftLon;
+  /** Right longitude */
+  protected final double rightLon;
+
+  /** The cosine of the middle latitude */
+  protected final double cosMiddleLat;
+
+  /** The lower right hand corner point */
+  protected final GeoPoint LRHC;
+  /** The lower left hand corner point */
+  protected final GeoPoint LLHC;
+
+  /** The bottom plane */
+  protected final SidedPlane bottomPlane;
+  /** The left plane */
+  protected final SidedPlane leftPlane;
+  /** The right plane */
+  protected final SidedPlane rightPlane;
+
+  /** Notable points for the bottom plane */
+  protected final GeoPoint[] bottomPlanePoints;
+  /** Notable points for the left plane */
+  protected final GeoPoint[] leftPlanePoints;
+  /** Notable points for the right plane */
+  protected final GeoPoint[] rightPlanePoints;
+
+  /** Center point */
+  protected final GeoPoint centerPoint;
+
+  /** Composite left/right bounds */
+  protected final EitherBound eitherBound;
+
+  /** A point on the edge */
+  protected final GeoPoint[] edgePoints;
+
+  /**
+   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}.
+   * Horizontal angle must be greater than or equal to PI.
+   */
+  public GeoWideNorthRectangle(final PlanetModel planetModel, final double bottomLat, final double leftLon, double rightLon) {
+    super(planetModel);
+    // Argument checking
+    if (bottomLat > Math.PI * 0.5 || bottomLat < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Bottom latitude out of range");
+    if (leftLon < -Math.PI || leftLon > Math.PI)
+      throw new IllegalArgumentException("Left longitude out of range");
+    if (rightLon < -Math.PI || rightLon > Math.PI)
+      throw new IllegalArgumentException("Right longitude out of range");
+    double extent = rightLon - leftLon;
+    if (extent < 0.0) {
+      extent += 2.0 * Math.PI;
+    }
+    if (extent < Math.PI)
+      throw new IllegalArgumentException("Width of rectangle too small");
+
+    this.bottomLat = bottomLat;
+    this.leftLon = leftLon;
+    this.rightLon = rightLon;
+
+    final double sinBottomLat = Math.sin(bottomLat);
+    final double cosBottomLat = Math.cos(bottomLat);
+    final double sinLeftLon = Math.sin(leftLon);
+    final double cosLeftLon = Math.cos(leftLon);
+    final double sinRightLon = Math.sin(rightLon);
+    final double cosRightLon = Math.cos(rightLon);
+
+    // Now build the four points
+    this.LRHC = new GeoPoint(planetModel, sinBottomLat, sinRightLon, cosBottomLat, cosRightLon, bottomLat, rightLon);
+    this.LLHC = new GeoPoint(planetModel, sinBottomLat, sinLeftLon, cosBottomLat, cosLeftLon, bottomLat, leftLon);
+
+    final double middleLat = (Math.PI * 0.5 + bottomLat) * 0.5;
+    final double sinMiddleLat = Math.sin(middleLat);
+    this.cosMiddleLat = Math.cos(middleLat);
+    // Normalize
+    while (leftLon > rightLon) {
+      rightLon += Math.PI * 2.0;
+    }
+    final double middleLon = (leftLon + rightLon) * 0.5;
+    final double sinMiddleLon = Math.sin(middleLon);
+    final double cosMiddleLon = Math.cos(middleLon);
+
+    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinMiddleLon, cosMiddleLat, cosMiddleLon);
+
+    this.bottomPlane = new SidedPlane(centerPoint, planetModel, sinBottomLat);
+    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
+    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
+
+    this.bottomPlanePoints = new GeoPoint[]{LLHC, LRHC};
+    this.leftPlanePoints = new GeoPoint[]{planetModel.NORTH_POLE, LLHC};
+    this.rightPlanePoints = new GeoPoint[]{planetModel.NORTH_POLE, LRHC};
+
+    this.eitherBound = new EitherBound();
+    this.edgePoints = new GeoPoint[]{planetModel.NORTH_POLE};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    final double newTopLat = Math.PI * 0.5;
+    final double newBottomLat = bottomLat - angle;
+    // Figuring out when we escalate to a special case requires some prefiguring
+    double currentLonSpan = rightLon - leftLon;
+    if (currentLonSpan < 0.0)
+      currentLonSpan += Math.PI * 2.0;
+    double newLeftLon = leftLon - angle;
+    double newRightLon = rightLon + angle;
+    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
+      newLeftLon = -Math.PI;
+      newRightLon = Math.PI;
+    }
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return
+        bottomPlane.isWithin(x, y, z) &&
+            (leftPlane.isWithin(x, y, z) ||
+                rightPlane.isWithin(x, y, z));
+  }
+
+  @Override
+  public double getRadius() {
+    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
+    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
+    // the distance to the right or left edge from the center.
+    final double centerAngle = (rightLon - (rightLon + leftLon) * 0.5) * cosMiddleLat;
+    final double bottomAngle = centerPoint.arcDistance(LLHC);
+    return Math.max(centerAngle, bottomAngle);
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    return centerPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    // Right and left bounds are essentially independent hemispheres; crossing into the wrong part of one
+    // requires crossing into the right part of the other.  So intersection can ignore the left/right bounds.
+    return
+        p.intersects(planetModel, bottomPlane, notablePoints, bottomPlanePoints, bounds, eitherBound) ||
+            p.intersects(planetModel, leftPlane, notablePoints, leftPlanePoints, bounds, bottomPlane) ||
+            p.intersects(planetModel, rightPlane, notablePoints, rightPlanePoints, bounds, bottomPlane);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds.isWide()
+      .addHorizontalPlane(planetModel, bottomLat, bottomPlane, eitherBound)
+      .addVerticalPlane(planetModel, leftLon, leftPlane, bottomPlane)
+      .addVerticalPlane(planetModel, rightLon, rightPlane, bottomPlane)
+      .addPoint(LLHC).addPoint(LRHC).addPoint(planetModel.NORTH_POLE);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    //System.err.println(this+" comparing to "+path);
+    final int insideRectangle = isShapeInsideBBox(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some inside");
+      return OVERLAPS;
+    }
+
+    final boolean insideShape = path.isWithin(planetModel.NORTH_POLE);
+
+    if (insideRectangle == ALL_INSIDE && insideShape) {
+      //System.err.println(" both inside each other");
+      return OVERLAPS;
+    }
+
+    if (
+        path.intersects(bottomPlane, bottomPlanePoints, eitherBound) ||
+            path.intersects(leftPlane, leftPlanePoints, bottomPlane) ||
+            path.intersects(rightPlane, rightPlanePoints, bottomPlane)) {
+      //System.err.println(" edges intersect");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      //System.err.println(" shape inside rectangle");
+      return WITHIN;
+    }
+
+    if (insideShape) {
+      //System.err.println(" rectangle inside shape");
+      return CONTAINS;
+    }
+
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    final double bottomDistance = distanceStyle.computeDistance(planetModel, bottomPlane, x,y,z, eitherBound);
+    // Because the rectangle exceeds 180 degrees, it is safe to compute the horizontally 
+    // unbounded distance to both the left and the right and only take the minimum of the two.
+    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, bottomPlane);
+    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, bottomPlane);
+    
+    final double LRHCDistance = distanceStyle.computeDistance(LRHC, x,y,z);
+    final double LLHCDistance = distanceStyle.computeDistance(LLHC, x,y,z);
+    
+    return Math.min(
+      Math.min(
+        bottomDistance,
+        Math.min(leftDistance, rightDistance)),
+      Math.min(LRHCDistance, LLHCDistance));
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoWideNorthRectangle))
+      return false;
+    GeoWideNorthRectangle other = (GeoWideNorthRectangle) o;
+    return super.equals(other) && other.LLHC.equals(LLHC) && other.LRHC.equals(LRHC);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + LLHC.hashCode();
+    result = 31 * result + LRHC.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoWideNorthRectangle: {planetmodel="+planetModel+", bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
+  }
+
+  /** Membership implementation representing a wide (more than 180 degree) bound.
+   */
+  protected class EitherBound implements Membership {
+    /** Constructor.
+     */
+    public EitherBound() {
+    }
+
+    @Override
+    public boolean isWithin(final Vector v) {
+      return leftPlane.isWithin(v) || rightPlane.isWithin(v);
+    }
+
+    @Override
+    public boolean isWithin(final double x, final double y, final double z) {
+      return leftPlane.isWithin(x, y, z) || rightPlane.isWithin(x, y, z);
+    }
+  }
+}
+  
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideRectangle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideRectangle.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideRectangle.java
new file mode 100755
index 0000000..c561747
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideRectangle.java
@@ -0,0 +1,319 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Bounding box wider than PI but limited on four sides (top lat,
+ * bottom lat, left lon, right lon).
+ *
+ * @lucene.internal
+ */
+public class GeoWideRectangle extends GeoBaseBBox {
+  /** The top latitude */
+  protected final double topLat;
+  /** The bottom latitude */
+  protected final double bottomLat;
+  /** The left longitude */
+  protected final double leftLon;
+  /** The right longitude */
+  protected final double rightLon;
+
+  /** Cosine of the middle latitude */
+  protected final double cosMiddleLat;
+
+  /** Upper left hand corner point */
+  protected final GeoPoint ULHC;
+  /** Lower right hand corner point */
+  protected final GeoPoint URHC;
+  /** Lower right hand corner point */
+  protected final GeoPoint LRHC;
+  /** Lower left hand corner point */
+  protected final GeoPoint LLHC;
+
+  /** Top plane */
+  protected final SidedPlane topPlane;
+  /** Bottom plane */
+  protected final SidedPlane bottomPlane;
+  /** Left plane */
+  protected final SidedPlane leftPlane;
+  /** Right plane */
+  protected final SidedPlane rightPlane;
+
+  /** Top plane's notable points */
+  protected final GeoPoint[] topPlanePoints;
+  /** Bottom plane's notable points */
+  protected final GeoPoint[] bottomPlanePoints;
+  /** Left plane's notable points */
+  protected final GeoPoint[] leftPlanePoints;
+  /** Right plane's notable points */
+  protected final GeoPoint[] rightPlanePoints;
+
+  /** Center point */
+  protected final GeoPoint centerPoint;
+
+  /** Combined left/right bounds */
+  protected final EitherBound eitherBound;
+
+  /** A point on the edge */
+  protected final GeoPoint[] edgePoints;
+
+  /**
+   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}.
+   * Horizontal angle must be greater than or equal to PI.
+   */
+  public GeoWideRectangle(final PlanetModel planetModel, final double topLat, final double bottomLat, final double leftLon, double rightLon) {
+    super(planetModel);
+    // Argument checking
+    if (topLat > Math.PI * 0.5 || topLat < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Top latitude out of range");
+    if (bottomLat > Math.PI * 0.5 || bottomLat < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Bottom latitude out of range");
+    if (topLat < bottomLat)
+      throw new IllegalArgumentException("Top latitude less than bottom latitude");
+    if (leftLon < -Math.PI || leftLon > Math.PI)
+      throw new IllegalArgumentException("Left longitude out of range");
+    if (rightLon < -Math.PI || rightLon > Math.PI)
+      throw new IllegalArgumentException("Right longitude out of range");
+    double extent = rightLon - leftLon;
+    if (extent < 0.0) {
+      extent += 2.0 * Math.PI;
+    }
+    if (extent < Math.PI)
+      throw new IllegalArgumentException("Width of rectangle too small");
+
+    this.topLat = topLat;
+    this.bottomLat = bottomLat;
+    this.leftLon = leftLon;
+    this.rightLon = rightLon;
+
+    final double sinTopLat = Math.sin(topLat);
+    final double cosTopLat = Math.cos(topLat);
+    final double sinBottomLat = Math.sin(bottomLat);
+    final double cosBottomLat = Math.cos(bottomLat);
+    final double sinLeftLon = Math.sin(leftLon);
+    final double cosLeftLon = Math.cos(leftLon);
+    final double sinRightLon = Math.sin(rightLon);
+    final double cosRightLon = Math.cos(rightLon);
+
+    // Now build the four points
+    this.ULHC = new GeoPoint(planetModel, sinTopLat, sinLeftLon, cosTopLat, cosLeftLon, topLat, leftLon);
+    this.URHC = new GeoPoint(planetModel, sinTopLat, sinRightLon, cosTopLat, cosRightLon, topLat, rightLon);
+    this.LRHC = new GeoPoint(planetModel, sinBottomLat, sinRightLon, cosBottomLat, cosRightLon, bottomLat, rightLon);
+    this.LLHC = new GeoPoint(planetModel, sinBottomLat, sinLeftLon, cosBottomLat, cosLeftLon, bottomLat, leftLon);
+
+    final double middleLat = (topLat + bottomLat) * 0.5;
+    final double sinMiddleLat = Math.sin(middleLat);
+    this.cosMiddleLat = Math.cos(middleLat);
+    // Normalize
+    while (leftLon > rightLon) {
+      rightLon += Math.PI * 2.0;
+    }
+    final double middleLon = (leftLon + rightLon) * 0.5;
+    final double sinMiddleLon = Math.sin(middleLon);
+    final double cosMiddleLon = Math.cos(middleLon);
+
+    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinMiddleLon, cosMiddleLat, cosMiddleLon);
+
+    this.topPlane = new SidedPlane(centerPoint, planetModel, sinTopLat);
+    this.bottomPlane = new SidedPlane(centerPoint, planetModel, sinBottomLat);
+    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
+    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
+
+    this.topPlanePoints = new GeoPoint[]{ULHC, URHC};
+    this.bottomPlanePoints = new GeoPoint[]{LLHC, LRHC};
+    this.leftPlanePoints = new GeoPoint[]{ULHC, LLHC};
+    this.rightPlanePoints = new GeoPoint[]{URHC, LRHC};
+
+    this.eitherBound = new EitherBound();
+
+    this.edgePoints = new GeoPoint[]{ULHC};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    final double newTopLat = topLat + angle;
+    final double newBottomLat = bottomLat - angle;
+    // Figuring out when we escalate to a special case requires some prefiguring
+    double currentLonSpan = rightLon - leftLon;
+    if (currentLonSpan < 0.0)
+      currentLonSpan += Math.PI * 2.0;
+    double newLeftLon = leftLon - angle;
+    double newRightLon = rightLon + angle;
+    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
+      newLeftLon = -Math.PI;
+      newRightLon = Math.PI;
+    }
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return topPlane.isWithin(x, y, z) &&
+        bottomPlane.isWithin(x, y, z) &&
+        (leftPlane.isWithin(x, y, z) ||
+            rightPlane.isWithin(x, y, z));
+  }
+
+  @Override
+  public double getRadius() {
+    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
+    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
+    // the distance to the right or left edge from the center.
+    final double centerAngle = (rightLon - (rightLon + leftLon) * 0.5) * cosMiddleLat;
+    final double topAngle = centerPoint.arcDistance(URHC);
+    final double bottomAngle = centerPoint.arcDistance(LLHC);
+    return Math.max(centerAngle, Math.max(topAngle, bottomAngle));
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  /**
+   * Returns the center of a circle into which the area will be inscribed.
+   *
+   * @return the center.
+   */
+  @Override
+  public GeoPoint getCenter() {
+    return centerPoint;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    // Right and left bounds are essentially independent hemispheres; crossing into the wrong part of one
+    // requires crossing into the right part of the other.  So intersection can ignore the left/right bounds.
+    return p.intersects(planetModel, topPlane, notablePoints, topPlanePoints, bounds, bottomPlane, eitherBound) ||
+        p.intersects(planetModel, bottomPlane, notablePoints, bottomPlanePoints, bounds, topPlane, eitherBound) ||
+        p.intersects(planetModel, leftPlane, notablePoints, leftPlanePoints, bounds, topPlane, bottomPlane) ||
+        p.intersects(planetModel, rightPlane, notablePoints, rightPlanePoints, bounds, topPlane, bottomPlane);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds.isWide()
+      .addHorizontalPlane(planetModel, topLat, topPlane, bottomPlane, eitherBound)
+      .addVerticalPlane(planetModel, rightLon, rightPlane, topPlane, bottomPlane)
+      .addHorizontalPlane(planetModel, bottomLat, bottomPlane, topPlane, eitherBound)
+      .addVerticalPlane(planetModel, leftLon, leftPlane, topPlane, bottomPlane)
+      .addPoint(ULHC).addPoint(URHC).addPoint(LRHC).addPoint(LLHC);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    //System.err.println(this+" comparing to "+path);
+    final int insideRectangle = isShapeInsideBBox(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some inside");
+      return OVERLAPS;
+    }
+
+    final boolean insideShape = path.isWithin(ULHC);
+
+    if (insideRectangle == ALL_INSIDE && insideShape) {
+      //System.err.println(" both inside each other");
+      return OVERLAPS;
+    }
+
+    if (path.intersects(topPlane, topPlanePoints, bottomPlane, eitherBound) ||
+        path.intersects(bottomPlane, bottomPlanePoints, topPlane, eitherBound) ||
+        path.intersects(leftPlane, leftPlanePoints, topPlane, bottomPlane) ||
+        path.intersects(rightPlane, rightPlanePoints, topPlane, bottomPlane)) {
+      //System.err.println(" edges intersect");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      //System.err.println(" shape inside rectangle");
+      return WITHIN;
+    }
+
+    if (insideShape) {
+      //System.err.println(" rectangle inside shape");
+      return CONTAINS;
+    }
+
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    final double topDistance = distanceStyle.computeDistance(planetModel, topPlane, x,y,z, bottomPlane, eitherBound);
+    final double bottomDistance = distanceStyle.computeDistance(planetModel, bottomPlane, x,y,z, topPlane, eitherBound);
+    // Because the rectangle exceeds 180 degrees, it is safe to compute the horizontally 
+    // unbounded distance to both the left and the right and only take the minimum of the two.
+    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, topPlane, bottomPlane);
+    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, topPlane, bottomPlane);
+    
+    final double ULHCDistance = distanceStyle.computeDistance(ULHC, x,y,z);
+    final double URHCDistance = distanceStyle.computeDistance(URHC, x,y,z);
+    final double LRHCDistance = distanceStyle.computeDistance(LRHC, x,y,z);
+    final double LLHCDistance = distanceStyle.computeDistance(LLHC, x,y,z);
+    
+    return Math.min(
+      Math.min(
+        Math.min(topDistance, bottomDistance),
+        Math.min(leftDistance, rightDistance)),
+      Math.min(
+        Math.min(ULHCDistance, URHCDistance),
+        Math.min(LRHCDistance, LLHCDistance)));
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoWideRectangle))
+      return false;
+    GeoWideRectangle other = (GeoWideRectangle) o;
+    return super.equals(other) && other.ULHC.equals(ULHC) && other.LRHC.equals(LRHC);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + ULHC.hashCode();
+    result = 31 * result + LRHC.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoWideRectangle: {planetmodel=" + planetModel + ", toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + "), bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
+  }
+
+  /** A membership implementation representing a wide (more than 180) left/right bound.
+   */
+  protected class EitherBound implements Membership {
+    /** Constructor.
+      */
+    public EitherBound() {
+    }
+
+    @Override
+    public boolean isWithin(final Vector v) {
+      return leftPlane.isWithin(v) || rightPlane.isWithin(v);
+    }
+
+    @Override
+    public boolean isWithin(final double x, final double y, final double z) {
+      return leftPlane.isWithin(x, y, z) || rightPlane.isWithin(x, y, z);
+    }
+  }
+}
+  


[30/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 3a31a8c)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPath.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPath.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPath.java
deleted file mode 100755
index bc5b9cf..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPath.java
+++ /dev/null
@@ -1,797 +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.geo3d;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * GeoShape representing a path across the surface of the globe,
- * with a specified half-width.  Path is described by a series of points.
- * Distances are measured from the starting point along the path, and then at right
- * angles to the path.
- *
- * @lucene.experimental
- */
-public class GeoPath extends GeoBaseDistanceShape {
-  /** The cutoff angle (width) */
-  protected final double cutoffAngle;
-
-  /** Sine of cutoff angle */
-  protected final double sinAngle;
-  /** Cosine of cutoff angle */
-  protected final double cosAngle;
-
-  /** The original list of path points */
-  protected final List<GeoPoint> points = new ArrayList<GeoPoint>();
-  
-  /** A list of SegmentEndpoints */
-  protected List<SegmentEndpoint> endPoints;
-  /** A list of PathSegments */
-  protected List<PathSegment> segments;
-
-  /** A point on the edge */
-  protected GeoPoint[] edgePoints;
-
-  /** Set to true if path has been completely constructed */
-  protected boolean isDone = false;
-  
-  /** Constructor.
-   *@param planetModel is the planet model.
-   *@param maxCutoffAngle is the width of the path, measured as an angle.
-   *@param pathPoints are the points in the path.
-   */
-  public GeoPath(final PlanetModel planetModel, final double maxCutoffAngle, final GeoPoint[] pathPoints) {
-    this(planetModel, maxCutoffAngle);
-    Collections.addAll(points, pathPoints);
-    done();
-  }
-  
-  /** Piece-wise constructor.  Use in conjunction with addPoint() and done().
-   *@param planetModel is the planet model.
-   *@param maxCutoffAngle is the width of the path, measured as an angle.
-   */
-  public GeoPath(final PlanetModel planetModel, final double maxCutoffAngle) {
-    super(planetModel);
-    if (maxCutoffAngle <= 0.0 || maxCutoffAngle > Math.PI * 0.5)
-      throw new IllegalArgumentException("Cutoff angle out of bounds");
-    this.cutoffAngle = maxCutoffAngle;
-    this.cosAngle = Math.cos(maxCutoffAngle);
-    this.sinAngle = Math.sin(maxCutoffAngle);
-  }
-
-  /** Add a point to the path.
-   *@param lat is the latitude of the point.
-   *@param lon is the longitude of the point.
-   */
-  public void addPoint(final double lat, final double lon) {
-    if (isDone)
-      throw new IllegalStateException("Can't call addPoint() if done() already called");
-    points.add(new GeoPoint(planetModel, lat, lon));
-  }
-  
-  /** Complete the path.
-   */
-  public void done() {
-    if (isDone)
-      throw new IllegalStateException("Can't call done() twice");
-    if (points.size() == 0)
-      throw new IllegalArgumentException("Path must have at least one point");
-    isDone = true;
-
-    endPoints = new ArrayList<>(points.size());
-    segments = new ArrayList<>(points.size());
-    // Compute an offset to use for all segments.  This will be based on the minimum magnitude of
-    // the entire ellipsoid.
-    final double cutoffOffset = this.sinAngle * planetModel.getMinimumMagnitude();
-    
-    // First, build all segments.  We'll then go back and build corresponding segment endpoints.
-    GeoPoint lastPoint = null;
-    for (final GeoPoint end : points) {
-      if (lastPoint != null) {
-        final Plane normalizedConnectingPlane = new Plane(lastPoint, end);
-        if (normalizedConnectingPlane == null) {
-          continue;
-        }
-        segments.add(new PathSegment(planetModel, lastPoint, end, normalizedConnectingPlane, cutoffOffset));
-      }
-      lastPoint = end;
-    }
-    
-    if (segments.size() == 0) {
-      // Simple circle
-      double lat = points.get(0).getLatitude();
-      double lon = points.get(0).getLongitude();
-      // Compute two points on the circle, with the right angle from the center.  We'll use these
-      // to obtain the perpendicular plane to the circle.
-      double upperLat = lat + cutoffAngle;
-      double upperLon = lon;
-      if (upperLat > Math.PI * 0.5) {
-        upperLon += Math.PI;
-        if (upperLon > Math.PI)
-          upperLon -= 2.0 * Math.PI;
-        upperLat = Math.PI - upperLat;
-      }
-      double lowerLat = lat - cutoffAngle;
-      double lowerLon = lon;
-      if (lowerLat < -Math.PI * 0.5) {
-        lowerLon += Math.PI;
-        if (lowerLon > Math.PI)
-          lowerLon -= 2.0 * Math.PI;
-        lowerLat = -Math.PI - lowerLat;
-      }
-      final GeoPoint upperPoint = new GeoPoint(planetModel, upperLat, upperLon);
-      final GeoPoint lowerPoint = new GeoPoint(planetModel, lowerLat, lowerLon);
-      final GeoPoint point = points.get(0);
-      
-      // Construct normal plane
-      final Plane normalPlane = Plane.constructNormalizedZPlane(upperPoint, lowerPoint, point);
-
-      final SegmentEndpoint onlyEndpoint = new SegmentEndpoint(point, normalPlane, upperPoint, lowerPoint);
-      endPoints.add(onlyEndpoint);
-      this.edgePoints = new GeoPoint[]{onlyEndpoint.circlePlane.getSampleIntersectionPoint(planetModel, normalPlane)};
-      return;
-    }
-    
-    // Create segment endpoints.  Use an appropriate constructor for the start and end of the path.
-    for (int i = 0; i < segments.size(); i++) {
-      final PathSegment currentSegment = segments.get(i);
-      
-      if (i == 0) {
-        // Starting endpoint
-        final SegmentEndpoint startEndpoint = new SegmentEndpoint(currentSegment.start, 
-          currentSegment.startCutoffPlane, currentSegment.ULHC, currentSegment.LLHC);
-        endPoints.add(startEndpoint);
-        this.edgePoints = new GeoPoint[]{currentSegment.ULHC};
-        continue;
-      }
-      
-      // General intersection case
-      final PathSegment prevSegment = segments.get(i-1);
-      // We construct four separate planes, and evaluate which one includes all interior points with least overlap
-      final SidedPlane candidate1 = SidedPlane.constructNormalizedThreePointSidedPlane(currentSegment.start, prevSegment.URHC, currentSegment.ULHC, currentSegment.LLHC);
-      final SidedPlane candidate2 = SidedPlane.constructNormalizedThreePointSidedPlane(currentSegment.start, currentSegment.ULHC, currentSegment.LLHC, prevSegment.LRHC);
-      final SidedPlane candidate3 = SidedPlane.constructNormalizedThreePointSidedPlane(currentSegment.start, currentSegment.LLHC, prevSegment.LRHC, prevSegment.URHC);
-      final SidedPlane candidate4 = SidedPlane.constructNormalizedThreePointSidedPlane(currentSegment.start, prevSegment.LRHC, prevSegment.URHC, currentSegment.ULHC);
-
-      if (candidate1 == null && candidate2 == null && candidate3 == null && candidate4 == null) {
-        // The planes are identical.  We wouldn't need a circle at all except for the possibility of
-        // backing up, which is hard to detect here.
-        final SegmentEndpoint midEndpoint = new SegmentEndpoint(currentSegment.start, 
-          prevSegment.endCutoffPlane, currentSegment.startCutoffPlane, currentSegment.ULHC, currentSegment.LLHC);
-        //don't need a circle at all.  Special constructor...
-        endPoints.add(midEndpoint);
-      } else {
-        endPoints.add(new SegmentEndpoint(currentSegment.start,
-          prevSegment.endCutoffPlane, currentSegment.startCutoffPlane,
-          prevSegment.URHC, prevSegment.LRHC,
-          currentSegment.ULHC, currentSegment.LLHC,
-          candidate1, candidate2, candidate3, candidate4));
-      }
-    }
-    // Do final endpoint
-    final PathSegment lastSegment = segments.get(segments.size()-1);
-    endPoints.add(new SegmentEndpoint(lastSegment.end,
-      lastSegment.endCutoffPlane, lastSegment.URHC, lastSegment.LRHC));
-
-  }
-
-  @Override
-  protected double distance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    // Algorithm:
-    // (1) If the point is within any of the segments along the path, return that value.
-    // (2) If the point is within any of the segment end circles along the path, return that value.
-    double currentDistance = 0.0;
-    for (PathSegment segment : segments) {
-      double distance = segment.pathDistance(planetModel, distanceStyle, x,y,z);
-      if (distance != Double.MAX_VALUE)
-        return currentDistance + distance;
-      currentDistance += segment.fullPathDistance(distanceStyle);
-    }
-
-    int segmentIndex = 0;
-    currentDistance = 0.0;
-    for (SegmentEndpoint endpoint : endPoints) {
-      double distance = endpoint.pathDistance(distanceStyle, x, y, z);
-      if (distance != Double.MAX_VALUE)
-        return currentDistance + distance;
-      if (segmentIndex < segments.size())
-        currentDistance += segments.get(segmentIndex++).fullPathDistance(distanceStyle);
-    }
-
-    return Double.MAX_VALUE;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    double minDistance = Double.MAX_VALUE;
-    for (final SegmentEndpoint endpoint : endPoints) {
-      final double newDistance = endpoint.outsideDistance(distanceStyle, x,y,z);
-      if (newDistance < minDistance)
-        minDistance = newDistance;
-    }
-    for (final PathSegment segment : segments) {
-      final double newDistance = segment.outsideDistance(planetModel, distanceStyle, x, y, z);
-      if (newDistance < minDistance)
-        minDistance = newDistance;
-    }
-    return minDistance;
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    for (SegmentEndpoint pathPoint : endPoints) {
-      if (pathPoint.isWithin(x, y, z))
-        return true;
-    }
-    for (PathSegment pathSegment : segments) {
-      if (pathSegment.isWithin(x, y, z))
-        return true;
-    }
-    return false;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane plane, final GeoPoint[] notablePoints, final Membership... bounds) {
-    // We look for an intersection with any of the exterior edges of the path.
-    // We also have to look for intersections with the cones described by the endpoints.
-    // Return "true" if any such intersections are found.
-
-    // For plane intersections, the basic idea is to come up with an equation of the line that is
-    // the intersection (if any).  Then, find the intersections with the unit sphere (if any).  If
-    // any of the intersection points are within the bounds, then we've detected an intersection.
-    // Well, sort of.  We can detect intersections also due to overlap of segments with each other.
-    // But that's an edge case and we won't be optimizing for it.
-    //System.err.println(" Looking for intersection of plane "+plane+" with path "+this);
-    for (final SegmentEndpoint pathPoint : endPoints) {
-      if (pathPoint.intersects(planetModel, plane, notablePoints, bounds)) {
-        return true;
-      }
-    }
-
-    for (final PathSegment pathSegment : segments) {
-      if (pathSegment.intersects(planetModel, plane, notablePoints, bounds)) {
-        return true;
-      }
-    }
-
-    return false;
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    // For building bounds, order matters.  We want to traverse
-    // never more than 180 degrees longitude at a pop or we risk having the
-    // bounds object get itself inverted.  So do the edges first.
-    for (PathSegment pathSegment : segments) {
-      pathSegment.getBounds(planetModel, bounds);
-    }
-    for (SegmentEndpoint pathPoint : endPoints) {
-      pathPoint.getBounds(planetModel, bounds);
-    }
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoPath))
-      return false;
-    GeoPath p = (GeoPath) o;
-    if (!super.equals(p))
-      return false;
-    if (cutoffAngle != p.cutoffAngle)
-      return false;
-    return points.equals(p.points);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    long temp = Double.doubleToLongBits(cutoffAngle);
-    result = 31 * result + (int) (temp ^ (temp >>> 32));
-    result = 31 * result + points.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoPath: {planetmodel=" + planetModel+", width=" + cutoffAngle + "(" + cutoffAngle * 180.0 / Math.PI + "), points={" + points + "}}";
-  }
-
-  /**
-   * This is precalculated data for segment endpoint.
-   * Note well: This is not necessarily a circle.  There are four cases:
-   * (1) The path consists of a single endpoint.  In this case, we build a simple circle with the proper cutoff offset.
-   * (2) This is the end of a path.  The circle plane must be constructed to go through two supplied points and be perpendicular to a connecting plane.
-   * (2.5) Intersection, but the path on both sides is linear.  We generate a circle, but we use the cutoff planes to limit its influence in the straight line case.
-   * (3) This is an intersection in a path.  We are supplied FOUR planes.  If there are intersections within bounds for both upper and lower, then
-   *    we generate no circle at all.  If there is one intersection only, then we generate a plane that includes that intersection, as well as the remaining
-   *    cutoff plane/edge plane points.
-   */
-  public static class SegmentEndpoint {
-    /** The center point of the endpoint */
-    public final GeoPoint point;
-    /** A plane describing the circle */
-    public final SidedPlane circlePlane;
-    /** Pertinent cutoff planes from adjoining segments */
-    public final Membership[] cutoffPlanes;
-    /** Notable points for this segment endpoint */
-    public final GeoPoint[] notablePoints;
-    /** No notable points from the circle itself */
-    public final static GeoPoint[] circlePoints = new GeoPoint[0];
-    /** Null membership */
-    public final static Membership[] NO_MEMBERSHIP = new Membership[0];
-    
-    /** Base case.  Does nothing at all.
-     */
-    public SegmentEndpoint(final GeoPoint point) {
-      this.point = point;
-      this.circlePlane = null;
-      this.cutoffPlanes = null;
-      this.notablePoints = null;
-    }
-    
-    /** Constructor for case (1).
-     * Generate a simple circle cutoff plane.
-     *@param point is the center point.
-     *@param upperPoint is a point that must be on the circle plane.
-     *@param lowerPoint is another point that must be on the circle plane.
-     */
-    public SegmentEndpoint(final GeoPoint point, final Plane normalPlane, final GeoPoint upperPoint, final GeoPoint lowerPoint) {
-      this.point = point;
-      // Construct a sided plane that goes through the two points and whose normal is in the normalPlane.
-      this.circlePlane = SidedPlane.constructNormalizedPerpendicularSidedPlane(point, normalPlane, upperPoint, lowerPoint);
-      this.cutoffPlanes = NO_MEMBERSHIP;
-      this.notablePoints = circlePoints;
-    }
-    
-    /** Constructor for case (2).
-     * Generate an endpoint, given a single cutoff plane plus upper and lower edge points.
-     *@param point is the center point.
-     *@param cutoffPlane is the plane from the adjoining path segment marking the boundary between this endpoint and that segment.
-     *@param topEdgePoint is a point on the cutoffPlane that should be also on the circle plane.
-     *@param bottomEdgePoint is another point on the cutoffPlane that should be also on the circle plane.
-     */
-    public SegmentEndpoint(final GeoPoint point,
-      final SidedPlane cutoffPlane, final GeoPoint topEdgePoint, final GeoPoint bottomEdgePoint) {
-      this.point = point;
-      this.cutoffPlanes = new Membership[]{new SidedPlane(cutoffPlane)};
-      this.notablePoints = new GeoPoint[]{topEdgePoint, bottomEdgePoint};
-      // To construct the plane, we now just need D, which is simply the negative of the evaluation of the circle normal vector at one of the points.
-      this.circlePlane = SidedPlane.constructNormalizedPerpendicularSidedPlane(point, cutoffPlane, topEdgePoint, bottomEdgePoint);
-    }
-
-    /** Constructor for case (2.5).
-     * Generate an endpoint, given two cutoff planes plus upper and lower edge points.
-     *@param point is the center.
-     *@param cutoffPlane1 is one adjoining path segment cutoff plane.
-     *@param cutoffPlane2 is another adjoining path segment cutoff plane.
-     *@param topEdgePoint is a point on the cutoffPlane that should be also on the circle plane.
-     *@param bottomEdgePoint is another point on the cutoffPlane that should be also on the circle plane.
-     */
-    public SegmentEndpoint(final GeoPoint point,
-      final SidedPlane cutoffPlane1, final SidedPlane cutoffPlane2, final GeoPoint topEdgePoint, final GeoPoint bottomEdgePoint) {
-      this.point = point;
-      this.cutoffPlanes = new Membership[]{new SidedPlane(cutoffPlane1), new SidedPlane(cutoffPlane2)};
-      this.notablePoints = new GeoPoint[]{topEdgePoint, bottomEdgePoint};
-      // To construct the plane, we now just need D, which is simply the negative of the evaluation of the circle normal vector at one of the points.
-      this.circlePlane = SidedPlane.constructNormalizedPerpendicularSidedPlane(point, cutoffPlane1, topEdgePoint, bottomEdgePoint);
-    }
-    
-    /** Constructor for case (3).
-     * Generate an endpoint for an intersection, given four points.
-     *@param point is the center.
-     *@param prevCutoffPlane is the previous adjoining segment cutoff plane.
-     *@param nextCutoffPlane is the next path segment cutoff plane.
-     *@param notCand2Point is a point NOT on candidate2.
-     *@param notCand1Point is a point NOT on candidate1.
-     *@param notCand3Point is a point NOT on candidate3.
-     *@param notCand4Point is a point NOT on candidate4.
-     *@param candidate1 one of four candidate circle planes.
-     *@param candidate2 one of four candidate circle planes.
-     *@param candidate3 one of four candidate circle planes.
-     *@param candidate4 one of four candidate circle planes.
-     */
-    public SegmentEndpoint(final GeoPoint point,
-      final SidedPlane prevCutoffPlane, final SidedPlane nextCutoffPlane,
-      final GeoPoint notCand2Point, final GeoPoint notCand1Point,
-      final GeoPoint notCand3Point, final GeoPoint notCand4Point,
-      final SidedPlane candidate1, final SidedPlane candidate2, final SidedPlane candidate3, final SidedPlane candidate4) {
-      // Note: What we really need is a single plane that goes through all four points.
-      // Since that's not possible in the ellipsoid case (because three points determine a plane, not four), we
-      // need an approximation that at least creates a boundary that has no interruptions.
-      // There are three obvious choices for the third point: either (a) one of the two remaining points, or (b) the top or bottom edge
-      // intersection point.  (a) has no guarantee of continuity, while (b) is capable of producing something very far from a circle if
-      // the angle between segments is acute.
-      // The solution is to look for the side (top or bottom) that has an intersection within the shape.  We use the two points from
-      // the opposite side to determine the plane, AND we pick the third to be either of the two points on the intersecting side
-      // PROVIDED that the other point is within the final circle we come up with.
-      this.point = point;
-      
-      // We construct four separate planes, and evaluate which one includes all interior points with least overlap
-      // (Constructed beforehand because we need them for degeneracy check)
-
-      final boolean cand1IsOtherWithin = candidate1!=null?candidate1.isWithin(notCand1Point):false;
-      final boolean cand2IsOtherWithin = candidate2!=null?candidate2.isWithin(notCand2Point):false;
-      final boolean cand3IsOtherWithin = candidate3!=null?candidate3.isWithin(notCand3Point):false;
-      final boolean cand4IsOtherWithin = candidate4!=null?candidate4.isWithin(notCand4Point):false;
-      
-      if (cand1IsOtherWithin && cand2IsOtherWithin && cand3IsOtherWithin && cand4IsOtherWithin) {
-        // The only way we should see both within is if all four points are coplanar.  In that case, we default to the simplest treatment.
-        this.circlePlane = candidate1;  // doesn't matter which
-        this.notablePoints = new GeoPoint[]{notCand2Point, notCand3Point, notCand1Point, notCand4Point};
-        this.cutoffPlanes = new Membership[]{new SidedPlane(prevCutoffPlane), new SidedPlane(nextCutoffPlane)};
-      } else if (cand1IsOtherWithin) {
-        // Use candidate1, and DON'T include prevCutoffPlane in the cutoff planes list
-        this.circlePlane = candidate1;
-        this.notablePoints = new GeoPoint[]{notCand2Point, notCand3Point, notCand4Point};
-        this.cutoffPlanes = new Membership[]{new SidedPlane(nextCutoffPlane)};
-      } else if (cand2IsOtherWithin) {
-        // Use candidate2
-        this.circlePlane = candidate2;
-        this.notablePoints = new GeoPoint[]{notCand3Point, notCand4Point, notCand1Point};
-        this.cutoffPlanes = new Membership[]{new SidedPlane(nextCutoffPlane)};
-      } else if (cand3IsOtherWithin) {
-        this.circlePlane = candidate3;
-        this.notablePoints = new GeoPoint[]{notCand4Point, notCand1Point, notCand2Point};
-        this.cutoffPlanes = new Membership[]{new SidedPlane(prevCutoffPlane)};
-      } else if (cand4IsOtherWithin) {
-        this.circlePlane = candidate4;
-        this.notablePoints = new GeoPoint[]{notCand1Point, notCand2Point, notCand3Point};
-        this.cutoffPlanes = new Membership[]{new SidedPlane(prevCutoffPlane)};
-      } else {
-        // dunno what happened
-        throw new RuntimeException("Couldn't come up with a plane through three points that included the fourth");
-      }
-    }
-
-    /** Check if point is within this endpoint.
-     *@param point is the point.
-     *@return true of within.
-     */
-    public boolean isWithin(final Vector point) {
-      if (circlePlane == null)
-        return false;
-      if (!circlePlane.isWithin(point))
-        return false;
-      for (final Membership m : cutoffPlanes) {
-        if (!m.isWithin(point)) {
-          return false;
-        }
-      }
-      return true;
-    }
-
-    /** Check if point is within this endpoint.
-     *@param x is the point x.
-     *@param y is the point y.
-     *@param z is the point z.
-     *@return true of within.
-     */
-    public boolean isWithin(final double x, final double y, final double z) {
-      if (circlePlane == null)
-        return false;
-      if (!circlePlane.isWithin(x, y, z))
-        return false;
-      for (final Membership m : cutoffPlanes) {
-        if (!m.isWithin(x,y,z)) {
-          return false;
-        }
-      }
-      return true;
-    }
-
-    /** Compute interior path distance.
-     *@param distanceStyle is the distance style.
-     *@param x is the point x.
-     *@param y is the point y.
-     *@param z is the point z.
-     *@return the distance metric.
-     */
-    public double pathDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-      if (!isWithin(x,y,z))
-        return Double.MAX_VALUE;
-      return distanceStyle.computeDistance(this.point, x, y, z);
-    }
-
-    /** Compute external distance.
-     *@param distanceStyle is the distance style.
-     *@param x is the point x.
-     *@param y is the point y.
-     *@param z is the point z.
-     *@return the distance metric.
-     */
-    public double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-      return distanceStyle.computeDistance(this.point, x, y, z);
-    }
-
-    /** Determine if this endpoint intersects a specified plane.
-     *@param planetModel is the planet model.
-     *@param p is the plane.
-     *@param notablePoints are the points associated with the plane.
-     *@param bounds are any bounds which the intersection must lie within.
-     *@return true if there is a matching intersection.
-     */
-    public boolean intersects(final PlanetModel planetModel, final Plane p, final GeoPoint[] notablePoints, final Membership[] bounds) {
-      //System.err.println("  looking for intersection between plane "+p+" and circle "+circlePlane+" on proper side of "+cutoffPlanes+" within "+bounds);
-      if (circlePlane == null)
-        return false;
-      return circlePlane.intersects(planetModel, p, notablePoints, this.notablePoints, bounds, this.cutoffPlanes);
-    }
-
-    /** Get the bounds for a segment endpoint.
-     *@param planetModel is the planet model.
-     *@param bounds are the bounds to be modified.
-     */
-    public void getBounds(final PlanetModel planetModel, Bounds bounds) {
-      bounds.addPoint(point);
-      if (circlePlane == null)
-        return;
-      bounds.addPlane(planetModel, circlePlane);
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      if (!(o instanceof SegmentEndpoint))
-        return false;
-      SegmentEndpoint other = (SegmentEndpoint) o;
-      return point.equals(other.point);
-    }
-
-    @Override
-    public int hashCode() {
-      return point.hashCode();
-    }
-
-    @Override
-    public String toString() {
-      return point.toString();
-    }
-  }
-
-  /**
-   * This is the pre-calculated data for a path segment.
-   */
-  public static class PathSegment {
-    /** Starting point of the segment */
-    public final GeoPoint start;
-    /** End point of the segment */
-    public final GeoPoint end;
-    /** Place to keep any complete segment distances we've calculated so far */
-    public final Map<DistanceStyle,Double> fullDistanceCache = new HashMap<DistanceStyle,Double>();
-    /** Normalized plane connecting the two points and going through world center */
-    public final Plane normalizedConnectingPlane;
-    /** Cutoff plane parallel to connecting plane representing one side of the path segment */
-    public final SidedPlane upperConnectingPlane;
-    /** Cutoff plane parallel to connecting plane representing the other side of the path segment */
-    public final SidedPlane lowerConnectingPlane;
-    /** Plane going through the center and start point, marking the start edge of the segment */
-    public final SidedPlane startCutoffPlane;
-    /** Plane going through the center and end point, marking the end edge of the segment */
-    public final SidedPlane endCutoffPlane;
-    /** Upper right hand corner of segment */
-    public final GeoPoint URHC;
-    /** Lower right hand corner of segment */
-    public final GeoPoint LRHC;
-    /** Upper left hand corner of segment */
-    public final GeoPoint ULHC;
-    /** Lower left hand corner of segment */
-    public final GeoPoint LLHC;
-    /** Notable points for the upper connecting plane */
-    public final GeoPoint[] upperConnectingPlanePoints;
-    /** Notable points for the lower connecting plane */
-    public final GeoPoint[] lowerConnectingPlanePoints;
-    /** Notable points for the start cutoff plane */
-    public final GeoPoint[] startCutoffPlanePoints;
-    /** Notable points for the end cutoff plane */
-    public final GeoPoint[] endCutoffPlanePoints;
-
-    /** Construct a path segment.
-     *@param planetModel is the planet model.
-     *@param start is the starting point.
-     *@param end is the ending point.
-     *@param normalizedConnectingPlane is the connecting plane.
-     *@param planeBoundingOffset is the linear offset from the connecting plane to either side.
-     */
-    public PathSegment(final PlanetModel planetModel, final GeoPoint start, final GeoPoint end,
-      final Plane normalizedConnectingPlane, final double planeBoundingOffset) {
-      this.start = start;
-      this.end = end;
-      this.normalizedConnectingPlane = normalizedConnectingPlane;
-        
-      // Either start or end should be on the correct side
-      upperConnectingPlane = new SidedPlane(start, normalizedConnectingPlane, -planeBoundingOffset);
-      lowerConnectingPlane = new SidedPlane(start, normalizedConnectingPlane, planeBoundingOffset);
-      // Cutoff planes use opposite endpoints as correct side examples
-      startCutoffPlane = new SidedPlane(end, normalizedConnectingPlane, start);
-      endCutoffPlane = new SidedPlane(start, normalizedConnectingPlane, end);
-      final Membership[] upperSide = new Membership[]{upperConnectingPlane};
-      final Membership[] lowerSide = new Membership[]{lowerConnectingPlane};
-      final Membership[] startSide = new Membership[]{startCutoffPlane};
-      final Membership[] endSide = new Membership[]{endCutoffPlane};
-      GeoPoint[] points;
-      points = upperConnectingPlane.findIntersections(planetModel, startCutoffPlane, lowerSide, endSide);
-      if (points.length == 0) {
-        throw new IllegalArgumentException("Some segment boundary points are off the ellipsoid; path too wide");
-      }
-      this.ULHC = points[0];
-      points = upperConnectingPlane.findIntersections(planetModel, endCutoffPlane, lowerSide, startSide);
-      if (points.length == 0) {
-        throw new IllegalArgumentException("Some segment boundary points are off the ellipsoid; path too wide");
-      }
-      this.URHC = points[0];
-      points = lowerConnectingPlane.findIntersections(planetModel, startCutoffPlane, upperSide, endSide);
-      if (points.length == 0) {
-        throw new IllegalArgumentException("Some segment boundary points are off the ellipsoid; path too wide");
-      }
-      this.LLHC = points[0];
-      points = lowerConnectingPlane.findIntersections(planetModel, endCutoffPlane, upperSide, startSide);
-      if (points.length == 0) {
-        throw new IllegalArgumentException("Some segment boundary points are off the ellipsoid; path too wide");
-      }
-      this.LRHC = points[0];
-      upperConnectingPlanePoints = new GeoPoint[]{ULHC, URHC};
-      lowerConnectingPlanePoints = new GeoPoint[]{LLHC, LRHC};
-      startCutoffPlanePoints = new GeoPoint[]{ULHC, LLHC};
-      endCutoffPlanePoints = new GeoPoint[]{URHC, LRHC};
-    }
-
-    /** Compute the full distance along this path segment.
-     *@param distanceStyle is the distance style.
-     *@return the distance metric.
-     */
-    public double fullPathDistance(final DistanceStyle distanceStyle) {
-      synchronized (fullDistanceCache) {
-        Double dist = fullDistanceCache.get(distanceStyle);
-        if (dist == null) {
-          dist = new Double(distanceStyle.computeDistance(start, end.x, end.y, end.z));
-          fullDistanceCache.put(distanceStyle, dist);
-        }
-        return dist.doubleValue();
-      }
-    }
-  
-    /** Check if point is within this segment.
-     *@param point is the point.
-     *@return true of within.
-     */
-    public boolean isWithin(final Vector point) {
-      return startCutoffPlane.isWithin(point) &&
-          endCutoffPlane.isWithin(point) &&
-          upperConnectingPlane.isWithin(point) &&
-          lowerConnectingPlane.isWithin(point);
-    }
-
-    /** Check if point is within this segment.
-     *@param x is the point x.
-     *@param y is the point y.
-     *@param z is the point z.
-     *@return true of within.
-     */
-    public boolean isWithin(final double x, final double y, final double z) {
-      return startCutoffPlane.isWithin(x, y, z) &&
-          endCutoffPlane.isWithin(x, y, z) &&
-          upperConnectingPlane.isWithin(x, y, z) &&
-          lowerConnectingPlane.isWithin(x, y, z);
-    }
-
-    /** Compute interior path distance.
-     *@param planetModel is the planet model.
-     *@param distanceStyle is the distance style.
-     *@param x is the point x.
-     *@param y is the point y.
-     *@param z is the point z.
-     *@return the distance metric.
-     */
-    public double pathDistance(final PlanetModel planetModel, final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-      if (!isWithin(x,y,z))
-        return Double.MAX_VALUE;
-
-      // (1) Compute normalizedPerpPlane.  If degenerate, then return point distance from start to point.
-      // Want no allocations or expensive operations!  so we do this the hard way
-      final double perpX = normalizedConnectingPlane.y * z - normalizedConnectingPlane.z * y;
-      final double perpY = normalizedConnectingPlane.z * x - normalizedConnectingPlane.x * z;
-      final double perpZ = normalizedConnectingPlane.x * y - normalizedConnectingPlane.y * x;
-      final double magnitude = Math.sqrt(perpX * perpX + perpY * perpY + perpZ * perpZ);
-      if (Math.abs(magnitude) < Vector.MINIMUM_RESOLUTION)
-        return distanceStyle.computeDistance(start, x,y,z);
-      final double normFactor = 1.0/magnitude;
-      final Plane normalizedPerpPlane = new Plane(perpX * normFactor, perpY * normFactor, perpZ * normFactor, 0.0);
-      
-      // Old computation: too expensive, because it calculates the intersection point twice.
-      //return distanceStyle.computeDistance(planetModel, normalizedConnectingPlane, x, y, z, startCutoffPlane, endCutoffPlane) +
-      //  distanceStyle.computeDistance(planetModel, normalizedPerpPlane, start.x, start.y, start.z, upperConnectingPlane, lowerConnectingPlane);
-
-      final GeoPoint[] intersectionPoints = normalizedConnectingPlane.findIntersections(planetModel, normalizedPerpPlane);
-      GeoPoint thePoint;
-      if (intersectionPoints.length == 0)
-        throw new RuntimeException("Can't find world intersection for point x="+x+" y="+y+" z="+z);
-      else if (intersectionPoints.length == 1)
-        thePoint = intersectionPoints[0];
-      else {
-        if (startCutoffPlane.isWithin(intersectionPoints[0]) && endCutoffPlane.isWithin(intersectionPoints[0]))
-          thePoint = intersectionPoints[0];
-        else if (startCutoffPlane.isWithin(intersectionPoints[1]) && endCutoffPlane.isWithin(intersectionPoints[1]))
-          thePoint = intersectionPoints[1];
-        else
-          throw new RuntimeException("Can't find world intersection for point x="+x+" y="+y+" z="+z);
-      }
-      return distanceStyle.computeDistance(thePoint, x, y, z) + distanceStyle.computeDistance(start, thePoint.x, thePoint.y, thePoint.z);
-    }
-
-    /** Compute external distance.
-     *@param planetModel is the planet model.
-     *@param distanceStyle is the distance style.
-     *@param x is the point x.
-     *@param y is the point y.
-     *@param z is the point z.
-     *@return the distance metric.
-     */
-    public double outsideDistance(final PlanetModel planetModel, final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-      final double upperDistance = distanceStyle.computeDistance(planetModel, upperConnectingPlane, x,y,z, lowerConnectingPlane, startCutoffPlane, endCutoffPlane);
-      final double lowerDistance = distanceStyle.computeDistance(planetModel, lowerConnectingPlane, x,y,z, upperConnectingPlane, startCutoffPlane, endCutoffPlane);
-      final double startDistance = distanceStyle.computeDistance(planetModel, startCutoffPlane, x,y,z, endCutoffPlane, lowerConnectingPlane, upperConnectingPlane);
-      final double endDistance = distanceStyle.computeDistance(planetModel, endCutoffPlane, x,y,z, startCutoffPlane, lowerConnectingPlane, upperConnectingPlane);
-      final double ULHCDistance = distanceStyle.computeDistance(ULHC, x,y,z);
-      final double URHCDistance = distanceStyle.computeDistance(URHC, x,y,z);
-      final double LLHCDistance = distanceStyle.computeDistance(LLHC, x,y,z);
-      final double LRHCDistance = distanceStyle.computeDistance(LRHC, x,y,z);
-      return Math.min(
-        Math.min(
-          Math.min(upperDistance,lowerDistance),
-          Math.min(startDistance,endDistance)),
-        Math.min(
-          Math.min(ULHCDistance, URHCDistance),
-          Math.min(LLHCDistance, LRHCDistance)));
-    }
-
-    /** Determine if this endpoint intersects a specified plane.
-     *@param planetModel is the planet model.
-     *@param p is the plane.
-     *@param notablePoints are the points associated with the plane.
-     *@param bounds are any bounds which the intersection must lie within.
-     *@return true if there is a matching intersection.
-     */
-    public boolean intersects(final PlanetModel planetModel, final Plane p, final GeoPoint[] notablePoints, final Membership[] bounds) {
-      return upperConnectingPlane.intersects(planetModel, p, notablePoints, upperConnectingPlanePoints, bounds, lowerConnectingPlane, startCutoffPlane, endCutoffPlane) ||
-          lowerConnectingPlane.intersects(planetModel, p, notablePoints, lowerConnectingPlanePoints, bounds, upperConnectingPlane, startCutoffPlane, endCutoffPlane);
-    }
-
-    /** Get the bounds for a segment endpoint.
-     *@param planetModel is the planet model.
-     *@param bounds are the bounds to be modified.
-     */
-    public void getBounds(final PlanetModel planetModel, Bounds bounds) {
-      // We need to do all bounding planes as well as corner points
-      bounds.addPoint(start).addPoint(end).addPoint(ULHC).addPoint(URHC).addPoint(LRHC).addPoint(LLHC);
-      bounds.addPlane(planetModel, upperConnectingPlane, lowerConnectingPlane, startCutoffPlane, endCutoffPlane);
-      bounds.addPlane(planetModel, lowerConnectingPlane, upperConnectingPlane, startCutoffPlane, endCutoffPlane);
-      bounds.addPlane(planetModel, startCutoffPlane, endCutoffPlane, upperConnectingPlane, lowerConnectingPlane);
-      bounds.addPlane(planetModel, endCutoffPlane, startCutoffPlane, upperConnectingPlane, lowerConnectingPlane);
-    }
-
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPoint.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPoint.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPoint.java
deleted file mode 100755
index e8a265d..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPoint.java
+++ /dev/null
@@ -1,193 +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.geo3d;
-    
-/**
- * This class represents a point on the surface of a sphere or ellipsoid.
- *
- * @lucene.experimental
- */
-public class GeoPoint extends Vector {
-  
-  // By making lazily-evaluated variables be "volatile", we guarantee atomicity when they
-  // are updated.  This is necessary if we are using these classes in a multi-thread fashion,
-  // because we don't try to synchronize for the lazy computation.
-  
-  /** This is the lazily-evaluated magnitude.  Some constructors include it, but others don't, and
-   * we try not to create extra computation by always computing it.  Does not need to be
-   * synchronized for thread safety, because depends wholly on immutable variables of this class. */
-  protected volatile double magnitude = Double.NEGATIVE_INFINITY;
-  /** Lazily-evaluated latitude.  Does not need to be
-   * synchronized for thread safety, because depends wholly on immutable variables of this class.  */
-  protected volatile double latitude = Double.NEGATIVE_INFINITY;
-  /** Lazily-evaluated longitude.   Does not need to be
-   * synchronized for thread safety, because depends wholly on immutable variables of this class.  */
-  protected volatile double longitude = Double.NEGATIVE_INFINITY;
-
-  /** Construct a GeoPoint from the trig functions of a lat and lon pair.
-   * @param planetModel is the planetModel to put the point on.
-   * @param sinLat is the sin of the latitude.
-   * @param sinLon is the sin of the longitude.
-   * @param cosLat is the cos of the latitude.
-   * @param cosLon is the cos of the longitude.
-   * @param lat is the latitude.
-   * @param lon is the longitude.
-   */
-  public GeoPoint(final PlanetModel planetModel, final double sinLat, final double sinLon, final double cosLat, final double cosLon, final double lat, final double lon) {
-    this(computeDesiredEllipsoidMagnitude(planetModel, cosLat * cosLon, cosLat * sinLon, sinLat),
-      cosLat * cosLon, cosLat * sinLon, sinLat, lat, lon);
-  }
-  
-  /** Construct a GeoPoint from the trig functions of a lat and lon pair.
-   * @param planetModel is the planetModel to put the point on.
-   * @param sinLat is the sin of the latitude.
-   * @param sinLon is the sin of the longitude.
-   * @param cosLat is the cos of the latitude.
-   * @param cosLon is the cos of the longitude.
-   */
-  public GeoPoint(final PlanetModel planetModel, final double sinLat, final double sinLon, final double cosLat, final double cosLon) {
-    this(computeDesiredEllipsoidMagnitude(planetModel, cosLat * cosLon, cosLat * sinLon, sinLat),
-      cosLat * cosLon, cosLat * sinLon, sinLat);
-  }
-
-  /** Construct a GeoPoint from a latitude/longitude pair.
-   * @param planetModel is the planetModel to put the point on.
-   * @param lat is the latitude.
-   * @param lon is the longitude.
-   */
-  public GeoPoint(final PlanetModel planetModel, final double lat, final double lon) {
-    this(planetModel, Math.sin(lat), Math.sin(lon), Math.cos(lat), Math.cos(lon), lat, lon);
-  }
-  
-  /** Construct a GeoPoint from a unit (x,y,z) vector and a magnitude.
-   * @param magnitude is the desired magnitude, provided to put the point on the ellipsoid.
-   * @param x is the unit x value.
-   * @param y is the unit y value.
-   * @param z is the unit z value.
-   * @param lat is the latitude.
-   * @param lon is the longitude.
-   */
-  public GeoPoint(final double magnitude, final double x, final double y, final double z, double lat, double lon) {
-    super(x * magnitude, y * magnitude, z * magnitude);
-    this.magnitude = magnitude;
-    if (lat > Math.PI * 0.5 || lat < -Math.PI * 0.5) {
-      throw new IllegalArgumentException("Latitude " + lat + " is out of range: must range from -Math.PI/2 to Math.PI/2");
-    }
-    if (lon < -Math.PI || lon > Math.PI) {
-      throw new IllegalArgumentException("Longitude " + lon + " is out of range: must range from -Math.PI to Math.PI");
-    }
-    this.latitude = lat;
-    this.longitude = lon;
-  }
-
-  /** Construct a GeoPoint from a unit (x,y,z) vector and a magnitude.
-   * @param magnitude is the desired magnitude, provided to put the point on the ellipsoid.
-   * @param x is the unit x value.
-   * @param y is the unit y value.
-   * @param z is the unit z value.
-   */
-  public GeoPoint(final double magnitude, final double x, final double y, final double z) {
-    super(x * magnitude, y * magnitude, z * magnitude);
-    this.magnitude = magnitude;
-  }
-  
-  /** Construct a GeoPoint from an (x,y,z) value.
-   * The (x,y,z) tuple must be on the desired ellipsoid.
-   * @param x is the ellipsoid point x value.
-   * @param y is the ellipsoid point y value.
-   * @param z is the ellipsoid point z value.
-   */
-  public GeoPoint(final double x, final double y, final double z) {
-    super(x, y, z);
-  }
-
-  /** Compute an arc distance between two points.
-   * Note: this is an angular distance, and not a surface distance, and is therefore independent of planet model.
-   * For surface distance, see {@link org.apache.lucene.geo3d.PlanetModel#surfaceDistance(GeoPoint, GeoPoint)}
-   * @param v is the second point.
-   * @return the angle, in radians, between the two points.
-   */
-  public double arcDistance(final GeoPoint v) {
-    return Tools.safeAcos(dotProduct(v)/(magnitude() * v.magnitude()));
-  }
-
-  /** Compute an arc distance between two points.
-   * @param x is the x part of the second point.
-   * @param y is the y part of the second point.
-   * @param z is the z part of the second point.
-   * @return the angle, in radians, between the two points.
-   */
-  public double arcDistance(final double x, final double y, final double z) {
-    return Tools.safeAcos(dotProduct(x,y,z)/(magnitude() * Vector.magnitude(x,y,z)));
-  }
-
-  /** Compute the latitude for the point.
-   * @return the latitude.
-   */
-  public double getLatitude() {
-    double lat = this.latitude;//volatile-read once
-    if (lat == Double.NEGATIVE_INFINITY)
-      this.latitude = lat = Math.asin(z / magnitude());
-    return lat;
-  }
-  
-  /** Compute the longitude for the point.
-   * @return the longitude value.  Uses 0.0 if there is no computable longitude.
-   */
-  public double getLongitude() {
-    double lon = this.longitude;//volatile-read once
-    if (lon == Double.NEGATIVE_INFINITY) {
-      if (Math.abs(x) < MINIMUM_RESOLUTION && Math.abs(y) < MINIMUM_RESOLUTION)
-        this.longitude = lon = 0.0;
-      else
-        this.longitude = lon = Math.atan2(y,x);
-    }
-    return lon;
-  }
-  
-  /** Compute the linear magnitude of the point.
-   * @return the magnitude.
-   */
-  @Override
-  public double magnitude() {
-    double mag = this.magnitude;//volatile-read once
-    if (mag == Double.NEGATIVE_INFINITY) {
-      this.magnitude = mag = super.magnitude();
-    }
-    return mag;
-  }
-  
-  /** Compute whether point matches another.
-   *@param x is the x value
-   *@param y is the y value
-   *@param z is the z value
-   *@return true if the same.
-   */
-  public boolean isIdentical(final double x, final double y, final double z) {
-    return Math.abs(this.x - x) < MINIMUM_RESOLUTION &&
-      Math.abs(this.y - y) < MINIMUM_RESOLUTION &&
-      Math.abs(this.z - z) < MINIMUM_RESOLUTION;
-  }
-  
-  @Override
-  public String toString() {
-    if (this.longitude == Double.NEGATIVE_INFINITY) {
-      return super.toString();
-    }
-    return "[lat="+getLatitude()+", lon="+getLongitude()+"]";
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPolygon.java
deleted file mode 100644
index 634406d..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPolygon.java
+++ /dev/null
@@ -1,26 +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.geo3d;
-
-/**
- * GeoPolygon interface description.
- *
- * @lucene.experimental
- */
-public interface GeoPolygon extends GeoMembershipShape {
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPolygonFactory.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPolygonFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPolygonFactory.java
deleted file mode 100755
index 0dc70a5..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPolygonFactory.java
+++ /dev/null
@@ -1,187 +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.geo3d;
-
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.List;
-
-/**
- * Class which constructs a GeoMembershipShape representing an arbitrary polygon.
- *
- * @lucene.experimental
- */
-public class GeoPolygonFactory {
-  private GeoPolygonFactory() {
-  }
-
-  /**
-   * Create a GeoMembershipShape of the right kind given the specified bounds.
-   *
-   * @param pointList        is a list of the GeoPoints to build an arbitrary polygon out of.
-   * @param convexPointIndex is the index of a single convex point whose conformation with
-   *                         its neighbors determines inside/outside for the entire polygon.
-   * @return a GeoPolygon corresponding to what was specified.
-   */
-  public static GeoPolygon makeGeoPolygon(final PlanetModel planetModel, final List<GeoPoint> pointList, final int convexPointIndex) {
-    // The basic operation uses a set of points, two points determining one particular edge, and a sided plane
-    // describing membership.
-    return buildPolygonShape(planetModel, pointList, convexPointIndex, getLegalIndex(convexPointIndex + 1, pointList.size()),
-        new SidedPlane(pointList.get(getLegalIndex(convexPointIndex - 1, pointList.size())),
-            pointList.get(convexPointIndex), pointList.get(getLegalIndex(convexPointIndex + 1, pointList.size()))),
-        false);
-  }
-
-  /** Build a GeoMembershipShape given points, starting edge, and whether starting edge is internal or not.
-   * @param pointsList        is a list of the GeoPoints to build an arbitrary polygon out of.
-   * @param startPointIndex is one of the points constituting the starting edge.
-   * @param endPointIndex is another of the points constituting the starting edge.
-   * @param startingEdge is the plane describing the starting edge.
-   * @param isInternalEdge is true if the specified edge is an internal one.
-   * @return a GeoMembershipShape corresponding to what was specified.
-   */
-  public static GeoPolygon buildPolygonShape(final PlanetModel planetModel, final List<GeoPoint> pointsList, final int startPointIndex, final int endPointIndex, final SidedPlane startingEdge, final boolean isInternalEdge) {
-    // Algorithm as follows:
-    // Start with sided edge.  Go through all points in some order.  For each new point, determine if the point is within all edges considered so far.
-    // If not, put it into a list of points for recursion.  If it is within, add new edge and keep going.
-    // Once we detect a point that is within, if there are points put aside for recursion, then call recursively.
-
-    // Current composite.  This is what we'll actually be returning.
-    final GeoCompositePolygon rval = new GeoCompositePolygon();
-
-    final List<GeoPoint> recursionList = new ArrayList<GeoPoint>();
-    final List<GeoPoint> currentList = new ArrayList<GeoPoint>();
-    final BitSet internalEdgeList = new BitSet();
-    final List<SidedPlane> currentPlanes = new ArrayList<SidedPlane>();
-
-    // Initialize the current list and current planes
-    currentList.add(pointsList.get(startPointIndex));
-    currentList.add(pointsList.get(endPointIndex));
-    internalEdgeList.set(currentPlanes.size(), isInternalEdge);
-    currentPlanes.add(startingEdge);
-
-    // Now, scan all remaining points, in order.  We'll use an index and just add to it.
-    for (int i = 0; i < pointsList.size() - 2; i++) {
-      GeoPoint newPoint = pointsList.get(getLegalIndex(i + endPointIndex + 1, pointsList.size()));
-      if (isWithin(newPoint, currentPlanes)) {
-        // Construct a sided plane based on the last two points, and the previous point
-        SidedPlane newBoundary = new SidedPlane(currentList.get(currentList.size() - 2), newPoint, currentList.get(currentList.size() - 1));
-        // Construct a sided plane based on the return trip
-        SidedPlane returnBoundary = new SidedPlane(currentList.get(currentList.size() - 1), currentList.get(0), newPoint);
-        // Verify that none of the points beyond the new point in the list are inside the polygon we'd
-        // be creating if we stopped making the current polygon right now.
-        boolean pointInside = false;
-        for (int j = i + 1; j < pointsList.size() - 2; j++) {
-          GeoPoint checkPoint = pointsList.get(getLegalIndex(j + endPointIndex + 1, pointsList.size()));
-          boolean isInside = true;
-          if (isInside && !newBoundary.isWithin(checkPoint))
-            isInside = false;
-          if (isInside && !returnBoundary.isWithin(checkPoint))
-            isInside = false;
-          if (isInside) {
-            for (SidedPlane plane : currentPlanes) {
-              if (!plane.isWithin(checkPoint)) {
-                isInside = false;
-                break;
-              }
-            }
-          }
-          if (isInside) {
-            pointInside = true;
-            break;
-          }
-        }
-        if (!pointInside) {
-          // Any excluded points?
-          boolean isInternalBoundary = recursionList.size() > 0;
-          if (isInternalBoundary) {
-            // Handle exclusion
-            recursionList.add(newPoint);
-            recursionList.add(currentList.get(currentList.size() - 1));
-            if (recursionList.size() == pointsList.size()) {
-              // We are trying to recurse with a list the same size as the one we started with.
-              // Clearly, the polygon cannot be constructed
-              throw new IllegalArgumentException("Polygon is illegal; cannot be decomposed into convex parts");
-            }
-            // We want the other side for the recursion
-            SidedPlane otherSideNewBoundary = new SidedPlane(newBoundary);
-            rval.addShape(buildPolygonShape(planetModel, recursionList, recursionList.size() - 2, recursionList.size() - 1, otherSideNewBoundary, true));
-            recursionList.clear();
-          }
-          currentList.add(newPoint);
-          internalEdgeList.set(currentPlanes.size(), isInternalBoundary);
-          currentPlanes.add(newBoundary);
-        } else {
-          recursionList.add(newPoint);
-        }
-      } else {
-        recursionList.add(newPoint);
-      }
-    }
-
-    boolean returnEdgeInternalBoundary = recursionList.size() > 0;
-    if (returnEdgeInternalBoundary) {
-      // The last step back to the start point had a recursion, so take care of that before we complete our work
-      recursionList.add(currentList.get(0));
-      recursionList.add(currentList.get(currentList.size() - 1));
-      if (recursionList.size() == pointsList.size()) {
-        // We are trying to recurse with a list the same size as the one we started with.
-        // Clearly, the polygon cannot be constructed
-        throw new IllegalArgumentException("Polygon is illegal; cannot be decomposed into convex parts");
-      }
-      // Construct a sided plane based on these two points, and the previous point
-      SidedPlane newBoundary = new SidedPlane(currentList.get(currentList.size() - 2), currentList.get(0), currentList.get(currentList.size() - 1));
-      // We want the other side for the recursion
-      SidedPlane otherSideNewBoundary = new SidedPlane(newBoundary);
-      rval.addShape(buildPolygonShape(planetModel, recursionList, recursionList.size() - 2, recursionList.size() - 1, otherSideNewBoundary, true));
-      recursionList.clear();
-    }
-    // Now, add in the current shape.
-    rval.addShape(new GeoConvexPolygon(planetModel, currentList, internalEdgeList, returnEdgeInternalBoundary));
-    //System.out.println("Done creating polygon");
-    return rval;
-  }
-
-  /** Check if a point is within a described list of planes.
-   *@param newPoint is the point. 
-   *@param currentPlanes is the list of planes.
-   *@return true if within.
-   */
-  protected static boolean isWithin(final GeoPoint newPoint, final List<SidedPlane> currentPlanes) {
-    for (SidedPlane p : currentPlanes) {
-      if (!p.isWithin(newPoint))
-        return false;
-    }
-    return true;
-  }
-
-  /** Convert raw point index into valid array position.
-   *@param index is the array index.
-   *@param size is the array size.
-   *@return an updated index.
-   */
-  protected static int getLegalIndex(int index, int size) {
-    while (index < 0) {
-      index += size;
-    }
-    while (index >= size) {
-      index -= size;
-    }
-    return index;
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoRectangle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoRectangle.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoRectangle.java
deleted file mode 100755
index fc2a531..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoRectangle.java
+++ /dev/null
@@ -1,288 +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.geo3d;
-
-/**
- * Bounding box limited on four sides (top lat, bottom lat, left lon, right lon).
- * The left-right maximum extent for this shape is PI; for anything larger, use
- * GeoWideRectangle.
- *
- * @lucene.internal
- */
-public class GeoRectangle extends GeoBaseBBox {
-  /** The top latitude of the rect */
-  protected final double topLat;
-  /** The bottom latitude of the rect */
-  protected final double bottomLat;
-  /** The left longitude of the rect */
-  protected final double leftLon;
-  /** The right longitude of the rect */
-  protected final double rightLon;
-  /** The cosine of a middle latitude */
-  protected final double cosMiddleLat;
-
-  /** The upper left hand corner point */
-  protected final GeoPoint ULHC;
-  /** The upper right hand corner point */
-  protected final GeoPoint URHC;
-  /** The lower right hand corner point */
-  protected final GeoPoint LRHC;
-  /** The lower left hand corner point */
-  protected final GeoPoint LLHC;
-
-  /** The top plane */
-  protected final SidedPlane topPlane;
-  /** The bottom plane */
-  protected final SidedPlane bottomPlane;
-  /** The left plane */
-  protected final SidedPlane leftPlane;
-  /** The right plane */
-  protected final SidedPlane rightPlane;
-
-  /** Notable points for the top plane */
-  protected final GeoPoint[] topPlanePoints;
-  /** Notable points for the bottom plane */
-  protected final GeoPoint[] bottomPlanePoints;
-  /** Notable points for the left plane */
-  protected final GeoPoint[] leftPlanePoints;
-  /** Notable points for the right plane */
-  protected final GeoPoint[] rightPlanePoints;
-
-  /** Center point */
-  protected final GeoPoint centerPoint;
-
-  /** Edge point for this rectangle */
-  protected final GeoPoint[] edgePoints;
-
-  /**
-   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
-   *@param planetModel is the planet model.
-   *@param topLat is the top latitude.
-   *@param bottomLat is the bottom latitude.
-   *@param leftLon is the left longitude.
-   *@param rightLon is the right longitude.
-   */
-  public GeoRectangle(final PlanetModel planetModel, final double topLat, final double bottomLat, final double leftLon, double rightLon) {
-    super(planetModel);
-    // Argument checking
-    if (topLat > Math.PI * 0.5 || topLat < -Math.PI * 0.5)
-      throw new IllegalArgumentException("Top latitude out of range");
-    if (bottomLat > Math.PI * 0.5 || bottomLat < -Math.PI * 0.5)
-      throw new IllegalArgumentException("Bottom latitude out of range");
-    if (topLat < bottomLat)
-      throw new IllegalArgumentException("Top latitude less than bottom latitude");
-    if (leftLon < -Math.PI || leftLon > Math.PI)
-      throw new IllegalArgumentException("Left longitude out of range");
-    if (rightLon < -Math.PI || rightLon > Math.PI)
-      throw new IllegalArgumentException("Right longitude out of range");
-    double extent = rightLon - leftLon;
-    if (extent < 0.0) {
-      extent += 2.0 * Math.PI;
-    }
-    if (extent > Math.PI)
-      throw new IllegalArgumentException("Width of rectangle too great");
-
-    this.topLat = topLat;
-    this.bottomLat = bottomLat;
-    this.leftLon = leftLon;
-    this.rightLon = rightLon;
-
-    final double sinTopLat = Math.sin(topLat);
-    final double cosTopLat = Math.cos(topLat);
-    final double sinBottomLat = Math.sin(bottomLat);
-    final double cosBottomLat = Math.cos(bottomLat);
-    final double sinLeftLon = Math.sin(leftLon);
-    final double cosLeftLon = Math.cos(leftLon);
-    final double sinRightLon = Math.sin(rightLon);
-    final double cosRightLon = Math.cos(rightLon);
-
-    // Now build the four points
-    this.ULHC = new GeoPoint(planetModel, sinTopLat, sinLeftLon, cosTopLat, cosLeftLon, topLat, leftLon);
-    this.URHC = new GeoPoint(planetModel, sinTopLat, sinRightLon, cosTopLat, cosRightLon, topLat, rightLon);
-    this.LRHC = new GeoPoint(planetModel, sinBottomLat, sinRightLon, cosBottomLat, cosRightLon, bottomLat, rightLon);
-    this.LLHC = new GeoPoint(planetModel, sinBottomLat, sinLeftLon, cosBottomLat, cosLeftLon, bottomLat, leftLon);
-
-    final double middleLat = (topLat + bottomLat) * 0.5;
-    final double sinMiddleLat = Math.sin(middleLat);
-    this.cosMiddleLat = Math.cos(middleLat);
-    // Normalize
-    while (leftLon > rightLon) {
-      rightLon += Math.PI * 2.0;
-    }
-    final double middleLon = (leftLon + rightLon) * 0.5;
-    final double sinMiddleLon = Math.sin(middleLon);
-    final double cosMiddleLon = Math.cos(middleLon);
-
-    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinMiddleLon, cosMiddleLat, cosMiddleLon);
-
-    this.topPlane = new SidedPlane(centerPoint, planetModel, sinTopLat);
-    this.bottomPlane = new SidedPlane(centerPoint, planetModel, sinBottomLat);
-    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
-    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
-
-    this.topPlanePoints = new GeoPoint[]{ULHC, URHC};
-    this.bottomPlanePoints = new GeoPoint[]{LLHC, LRHC};
-    this.leftPlanePoints = new GeoPoint[]{ULHC, LLHC};
-    this.rightPlanePoints = new GeoPoint[]{URHC, LRHC};
-
-    this.edgePoints = new GeoPoint[]{ULHC};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    final double newTopLat = topLat + angle;
-    final double newBottomLat = bottomLat - angle;
-    // Figuring out when we escalate to a special case requires some prefiguring
-    double currentLonSpan = rightLon - leftLon;
-    if (currentLonSpan < 0.0)
-      currentLonSpan += Math.PI * 2.0;
-    double newLeftLon = leftLon - angle;
-    double newRightLon = rightLon + angle;
-    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
-      newLeftLon = -Math.PI;
-      newRightLon = Math.PI;
-    }
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return topPlane.isWithin(x, y, z) &&
-        bottomPlane.isWithin(x, y, z) &&
-        leftPlane.isWithin(x, y, z) &&
-        rightPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public double getRadius() {
-    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
-    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
-    // the distance to the right or left edge from the center.
-    final double centerAngle = (rightLon - (rightLon + leftLon) * 0.5) * cosMiddleLat;
-    final double topAngle = centerPoint.arcDistance(URHC);
-    final double bottomAngle = centerPoint.arcDistance(LLHC);
-    return Math.max(centerAngle, Math.max(topAngle, bottomAngle));
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    return centerPoint;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    return p.intersects(planetModel, topPlane, notablePoints, topPlanePoints, bounds, bottomPlane, leftPlane, rightPlane) ||
-        p.intersects(planetModel, bottomPlane, notablePoints, bottomPlanePoints, bounds, topPlane, leftPlane, rightPlane) ||
-        p.intersects(planetModel, leftPlane, notablePoints, leftPlanePoints, bounds, rightPlane, topPlane, bottomPlane) ||
-        p.intersects(planetModel, rightPlane, notablePoints, rightPlanePoints, bounds, leftPlane, topPlane, bottomPlane);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds.addHorizontalPlane(planetModel, topLat, topPlane, bottomPlane, leftPlane, rightPlane)
-      .addVerticalPlane(planetModel, rightLon, rightPlane, topPlane, bottomPlane, leftPlane)
-      .addHorizontalPlane(planetModel, bottomLat, bottomPlane, topPlane, leftPlane, rightPlane)
-      .addVerticalPlane(planetModel, leftLon, leftPlane, topPlane, bottomPlane, rightPlane)
-      .addPoint(ULHC).addPoint(URHC).addPoint(LLHC).addPoint(LRHC);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    //System.err.println(this+" getrelationship with "+path);
-    final int insideRectangle = isShapeInsideBBox(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some inside");
-      return OVERLAPS;
-    }
-
-    final boolean insideShape = path.isWithin(ULHC);
-
-    if (insideRectangle == ALL_INSIDE && insideShape) {
-      //System.err.println(" inside of each other");
-      return OVERLAPS;
-    }
-
-    if (path.intersects(topPlane, topPlanePoints, bottomPlane, leftPlane, rightPlane) ||
-        path.intersects(bottomPlane, bottomPlanePoints, topPlane, leftPlane, rightPlane) ||
-        path.intersects(leftPlane, leftPlanePoints, topPlane, bottomPlane, rightPlane) ||
-        path.intersects(rightPlane, rightPlanePoints, leftPlane, topPlane, bottomPlane)) {
-      //System.err.println(" edges intersect");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      //System.err.println(" shape inside rectangle");
-      return WITHIN;
-    }
-
-    if (insideShape) {
-      //System.err.println(" shape contains rectangle");
-      return CONTAINS;
-    }
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    final double topDistance = distanceStyle.computeDistance(planetModel, topPlane, x,y,z, bottomPlane, leftPlane, rightPlane);
-    final double bottomDistance = distanceStyle.computeDistance(planetModel, bottomPlane, x,y,z, topPlane, leftPlane, rightPlane);
-    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, rightPlane, topPlane, bottomPlane);
-    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, leftPlane, topPlane, bottomPlane);
-    
-    final double ULHCDistance = distanceStyle.computeDistance(ULHC, x,y,z);
-    final double URHCDistance = distanceStyle.computeDistance(URHC, x,y,z);
-    final double LRHCDistance = distanceStyle.computeDistance(LRHC, x,y,z);
-    final double LLHCDistance = distanceStyle.computeDistance(LLHC, x,y,z);
-    
-    return Math.min(
-      Math.min(
-        Math.min(topDistance, bottomDistance),
-        Math.min(leftDistance, rightDistance)),
-      Math.min(
-        Math.min(ULHCDistance, URHCDistance),
-        Math.min(LRHCDistance, LLHCDistance)));
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoRectangle))
-      return false;
-    GeoRectangle other = (GeoRectangle) o;
-    return super.equals(other) && other.ULHC.equals(ULHC) && other.LRHC.equals(LRHC);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result  + ULHC.hashCode();
-    result = 31 * result  + LRHC.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoRectangle: {planetmodel="+planetModel+", toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + "), bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
-  }
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoShape.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoShape.java
deleted file mode 100755
index 21cdba3..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoShape.java
+++ /dev/null
@@ -1,63 +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.geo3d;
-
-/**
- * Generic shape.  This describes methods that help GeoAreas figure out
- * how they interact with a shape, for the purposes of coming up with a
- * set of geo hash values.
- *
- * @lucene.experimental
- */
-public interface GeoShape extends Membership {
-
-  /**
-   * Return a sample point that is on the outside edge/boundary of the shape.
-   *
-   * @return samples of all edge points from distinct edge sections.  Typically one point
-   * is returned, but zero or two are also possible.
-   */
-  public GeoPoint[] getEdgePoints();
-
-  /**
-   * Assess whether a plane, within the provided bounds, intersects
-   * with the shape.  Note well that this method is allowed to return "true"
-   * if there are internal edges of a composite shape which intersect the plane.
-   * Doing this can cause getRelationship() for most GeoBBox shapes to return
-   * OVERLAPS rather than the more correct CONTAINS, but that cannot be
-   * helped for some complex shapes that are built out of overlapping parts.
-   *
-   * @param plane         is the plane to assess for intersection with the shape's edges or
-   *                      bounding curves.
-   * @param notablePoints represents the intersections of the plane with the supplied
-   *                      bounds.  These are used to disambiguate when two planes are identical and it needs
-   *                      to be determined whether any points exist that fulfill all the bounds.
-   * @param bounds        are a set of bounds that define an area that an
-   *                      intersection must be within in order to qualify (provided by a GeoArea).
-   * @return true if there's such an intersection, false if not.
-   */
-  public boolean intersects(final Plane plane, final GeoPoint[] notablePoints, final Membership... bounds);
-
-  /**
-   * Compute bounds for the shape.
-   *
-   * @param bounds is the input bounds object.
-   *             The input object will be modified.
-   */
-  public void getBounds(final Bounds bounds);
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoSizeable.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoSizeable.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoSizeable.java
deleted file mode 100755
index e8c0ebb..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoSizeable.java
+++ /dev/null
@@ -1,40 +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.geo3d;
-
-/**
- * Some shapes can compute radii of a geocircle in which they are inscribed.
- *
- * @lucene.experimental
- */
-public interface GeoSizeable {
-  /**
-   * Returns the radius of a circle into which the GeoSizeable area can
-   * be inscribed.
-   *
-   * @return the radius.
-   */
-  public double getRadius();
-
-  /**
-   * Returns the center of a circle into which the area will be inscribed.
-   *
-   * @return the center.
-   */
-  public GeoPoint getCenter();
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoSouthLatitudeZone.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoSouthLatitudeZone.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoSouthLatitudeZone.java
deleted file mode 100644
index 439dc1b..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoSouthLatitudeZone.java
+++ /dev/null
@@ -1,168 +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.geo3d;
-
-/**
- * This GeoBBox represents an area rectangle limited only in north latitude.
- *
- * @lucene.internal
- */
-public class GeoSouthLatitudeZone extends GeoBaseBBox {
-  /** The top latitude of the zone */
-  protected final double topLat;
-  /** The cosine of the top latitude of the zone */
-  protected final double cosTopLat;
-  /** The top plane of the zone */
-  protected final SidedPlane topPlane;
-  /** An interior point of the zone */
-  protected final GeoPoint interiorPoint;
-  /** Notable points for the plane (none) */
-  protected final static GeoPoint[] planePoints = new GeoPoint[0];
-  /** A point on the top boundary */
-  protected final GeoPoint topBoundaryPoint;
-  /** Edge points; a reference to the topBoundaryPoint */
-  protected final GeoPoint[] edgePoints;
-
-  /** Constructor.
-   *@param planetModel is the planet model.
-   *@param topLat is the top latitude of the zone.
-   */
-  public GeoSouthLatitudeZone(final PlanetModel planetModel, final double topLat) {
-    super(planetModel);
-    this.topLat = topLat;
-
-    final double sinTopLat = Math.sin(topLat);
-    this.cosTopLat = Math.cos(topLat);
-
-    // Compute an interior point.  Pick one whose lat is between top and bottom.
-    final double middleLat = (topLat - Math.PI * 0.5) * 0.5;
-    final double sinMiddleLat = Math.sin(middleLat);
-    this.interiorPoint = new GeoPoint(planetModel, sinMiddleLat, 0.0, Math.sqrt(1.0 - sinMiddleLat * sinMiddleLat), 1.0);
-    this.topBoundaryPoint = new GeoPoint(planetModel, sinTopLat, 0.0, Math.sqrt(1.0 - sinTopLat * sinTopLat), 1.0);
-
-    this.topPlane = new SidedPlane(interiorPoint, planetModel, sinTopLat);
-
-    this.edgePoints = new GeoPoint[]{topBoundaryPoint};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    final double newTopLat = topLat + angle;
-    final double newBottomLat = -Math.PI * 0.5;
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, -Math.PI, Math.PI);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return topPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public double getRadius() {
-    // This is a bit tricky.  I guess we should interpret this as meaning the angle of a circle that
-    // would contain all the bounding box points, when starting in the "center".
-    if (topLat > 0.0)
-      return Math.PI;
-    double maxCosLat = cosTopLat;
-    return maxCosLat * Math.PI;
-  }
-
-  /**
-   * Returns the center of a circle into which the area will be inscribed.
-   *
-   * @return the center.
-   */
-  @Override
-  public GeoPoint getCenter() {
-    return interiorPoint;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    return p.intersects(planetModel, topPlane, notablePoints, planePoints, bounds);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds
-      .addHorizontalPlane(planetModel, topLat, topPlane);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    final int insideRectangle = isShapeInsideBBox(path);
-    if (insideRectangle == SOME_INSIDE)
-      return OVERLAPS;
-
-    final boolean insideShape = path.isWithin(topBoundaryPoint);
-
-    if (insideRectangle == ALL_INSIDE && insideShape)
-      return OVERLAPS;
-
-    // Second, the shortcut of seeing whether endpoints are in/out is not going to
-    // work with no area endpoints.  So we rely entirely on intersections.
-
-    if (path.intersects(topPlane, planePoints))
-      return OVERLAPS;
-
-    // There is another case for latitude zones only.  This is when the boundaries of the shape all fit
-    // within the zone, but the shape includes areas outside the zone crossing a pole.
-    // In this case, the above "overlaps" check is insufficient.  We also need to check a point on either boundary
-    // whether it is within the shape.  If both such points are within, then CONTAINS is the right answer.  If
-    // one such point is within, then OVERLAPS is the right answer.
-
-    if (insideShape)
-      return CONTAINS;
-
-    if (insideRectangle == ALL_INSIDE)
-      return WITHIN;
-
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    return distanceStyle.computeDistance(planetModel, topPlane, x,y,z);
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoSouthLatitudeZone))
-      return false;
-    GeoSouthLatitudeZone other = (GeoSouthLatitudeZone) o;
-    return super.equals(other) && other.topBoundaryPoint.equals(topBoundaryPoint);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + topBoundaryPoint.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoSouthLatitudeZone: {planetmodel="+planetModel+", toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + ")}";
-  }
-}
-


[26/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 3a31a8c)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XdYZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XdYZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XdYZSolid.java
deleted file mode 100644
index f6a2fa3..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XdYZSolid.java
+++ /dev/null
@@ -1,212 +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.geo3d;
-
-/**
- * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in Y
- *
- * @lucene.internal
- */
-public class XdYZSolid extends BaseXYZSolid {
-
-  /** Min-X plane */
-  protected final SidedPlane minXPlane;
-  /** Max-X plane */
-  protected final SidedPlane maxXPlane;
-  /** Y plane */
-  protected final Plane yPlane;
-  /** Min-Z plane */
-  protected final SidedPlane minZPlane;
-  /** Max-Z plane */
-  protected final SidedPlane maxZPlane;
-  
-  /** These are the edge points of the shape, which are defined to be at least one point on
-   * each surface area boundary.  In the case of a solid, this includes points which represent
-   * the intersection of XYZ bounding planes and the planet, as well as points representing
-   * the intersection of single bounding planes with the planet itself.
-   */
-  protected final GeoPoint[] edgePoints;
-
-  /** Notable points for YPlane */
-  protected final GeoPoint[] notableYPoints;
-
-  /**
-   * Sole constructor
-   *
-   *@param planetModel is the planet model.
-   *@param minX is the minimum X value.
-   *@param maxX is the maximum X value.
-   *@param Y is the Y value.
-   *@param minZ is the minimum Z value.
-   *@param maxZ is the maximum Z value.
-   */
-  public XdYZSolid(final PlanetModel planetModel,
-    final double minX,
-    final double maxX,
-    final double Y,
-    final double minZ,
-    final double maxZ) {
-    super(planetModel);
-    // Argument checking
-    if (maxX - minX < Vector.MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("X values in wrong order or identical");
-    if (maxZ - minZ < Vector.MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("Z values in wrong order or identical");
-
-    final double worldMinY = planetModel.getMinimumYValue();
-    final double worldMaxY = planetModel.getMaximumYValue();
-    
-    // Construct the planes
-    minXPlane = new SidedPlane(maxX,0.0,0.0,xUnitVector,-minX);
-    maxXPlane = new SidedPlane(minX,0.0,0.0,xUnitVector,-maxX);
-    yPlane = new Plane(yUnitVector,-Y);
-    minZPlane = new SidedPlane(0.0,0.0,maxZ,zUnitVector,-minZ);
-    maxZPlane = new SidedPlane(0.0,0.0,minZ,zUnitVector,-maxZ);
-      
-    // We need at least one point on the planet surface for each manifestation of the shape.
-    // There can be up to 2 (on opposite sides of the world).  But we have to go through
-    // 4 combinations of adjacent planes in order to find out if any have 2 intersection solution.
-    // Typically, this requires 4 square root operations. 
-    final GeoPoint[] minXY = minXPlane.findIntersections(planetModel,yPlane,maxXPlane,minZPlane,maxZPlane);
-    final GeoPoint[] maxXY = maxXPlane.findIntersections(planetModel,yPlane,minXPlane,minZPlane,maxZPlane);
-    final GeoPoint[] YminZ = yPlane.findIntersections(planetModel,minZPlane,maxZPlane,minXPlane,maxXPlane);
-    final GeoPoint[] YmaxZ = yPlane.findIntersections(planetModel,maxZPlane,minZPlane,minXPlane,maxXPlane);
-      
-    notableYPoints = glueTogether(minXY, maxXY, YminZ, YmaxZ);
-
-    // Now, compute the edge points.
-    // This is the trickiest part of setting up an XYZSolid.  We've computed intersections already, so
-    // we'll start there.  We know that at most there will be two disconnected shapes on the planet surface.
-    // But there's also a case where exactly one plane slices through the world, and none of the bounding plane
-    // intersections do.  Thus, if we don't find any of the edge intersection cases, we have to look for that last case.
-      
-    // We need to look at single-plane/world intersections.
-    // We detect these by looking at the world model and noting its x, y, and z bounds.
-    // The cases we are looking for are when the four corner points for any given
-    // plane are all outside of the world, AND that plane intersects the world.
-    // There are four corner points all told; we must evaluate these WRT the planet surface.
-    final boolean minXYminZ = planetModel.pointOutside(minX, Y, minZ);
-    final boolean minXYmaxZ = planetModel.pointOutside(minX, Y, maxZ);
-    final boolean maxXYminZ = planetModel.pointOutside(maxX, Y, minZ);
-    final boolean maxXYmaxZ = planetModel.pointOutside(maxX, Y, maxZ);
-
-    final GeoPoint[] yEdges;
-    if (Y - worldMinY >= -Vector.MINIMUM_RESOLUTION && Y - worldMaxY <= Vector.MINIMUM_RESOLUTION &&
-      minX < 0.0 && maxX > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
-      minXYminZ && minXYmaxZ && maxXYminZ && maxXYmaxZ) {
-      // Find any point on the minY plane that intersects the world
-      // First construct a perpendicular plane that will allow us to find a sample point.
-      // This plane is vertical and goes through the points (0,0,0) and (0,1,0)
-      // Then use it to compute a sample point.
-      final GeoPoint intPoint = yPlane.getSampleIntersectionPoint(planetModel, yVerticalPlane);
-      if (intPoint != null) {
-        yEdges = new GeoPoint[]{intPoint};
-      } else {
-        yEdges = EMPTY_POINTS;
-      }
-    } else {
-      yEdges = EMPTY_POINTS;
-    }
-
-    this.edgePoints = glueTogether(minXY, maxXY, YminZ, YmaxZ, yEdges);
-  }
-
-  @Override
-  protected GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-  
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return minXPlane.isWithin(x, y, z) &&
-      maxXPlane.isWithin(x, y, z) &&
-      yPlane.evaluateIsZero(x, y, z) &&
-      minZPlane.isWithin(x, y, z) &&
-      maxZPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    //System.err.println(this+" getrelationship with "+path);
-    final int insideRectangle = isShapeInsideArea(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some inside");
-      return OVERLAPS;
-    }
-
-    // Figure out if the entire XYZArea is contained by the shape.
-    final int insideShape = isAreaInsideShape(path);
-    if (insideShape == SOME_INSIDE) {
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
-      //System.err.println(" inside of each other");
-      return OVERLAPS;
-    }
-
-    if (path.intersects(yPlane, notableYPoints, minXPlane, maxXPlane, minZPlane, maxZPlane)) {
-      //System.err.println(" edges intersect");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      //System.err.println(" shape inside rectangle");
-      return WITHIN;
-    }
-
-    if (insideShape == ALL_INSIDE) {
-      //System.err.println(" shape contains rectangle");
-      return CONTAINS;
-    }
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof XdYZSolid))
-      return false;
-    XdYZSolid other = (XdYZSolid) o;
-    if (!super.equals(other)) {
-      return false;
-    }
-    return other.minXPlane.equals(minXPlane) &&
-      other.maxXPlane.equals(maxXPlane) &&
-      other.yPlane.equals(yPlane) &&
-      other.minZPlane.equals(minZPlane) &&
-      other.maxZPlane.equals(maxZPlane);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result  + minXPlane.hashCode();
-    result = 31 * result  + maxXPlane.hashCode();
-    result = 31 * result  + yPlane.hashCode();
-    result = 31 * result  + minZPlane.hashCode();
-    result = 31 * result  + maxZPlane.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "XdYZSolid: {planetmodel="+planetModel+", minXplane="+minXPlane+", maxXplane="+maxXPlane+", yplane="+yPlane+", minZplane="+minZPlane+", maxZplane="+maxZPlane+"}";
-  }
-  
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XdYdZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XdYdZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XdYdZSolid.java
deleted file mode 100644
index 562e5a6..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XdYdZSolid.java
+++ /dev/null
@@ -1,138 +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.geo3d;
-
-/**
- * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in Y and Z.
- * This figure, in fact, represents either zero, one, or two points, so the
- * actual data stored is minimal.
- *
- * @lucene.internal
- */
-public class XdYdZSolid extends BaseXYZSolid {
-
-  /** The points in this figure on the planet surface; also doubles for edge points */
-  protected final GeoPoint[] surfacePoints;
-  
-  /**
-   * Sole constructor
-   *
-   *@param planetModel is the planet model.
-   *@param minX is the minimum X value.
-   *@param maxX is the maximum X value.
-   *@param Y is the Y value.
-   *@param Z is the Z value.
-   */
-  public XdYdZSolid(final PlanetModel planetModel,
-    final double minX,
-    final double maxX,
-    final double Y,
-    final double Z) {
-    super(planetModel);
-    // Argument checking
-    if (maxX - minX < Vector.MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("X values in wrong order or identical");
-
-    // Build the planes and intersect them.
-    final Plane yPlane = new Plane(yUnitVector,-Y);
-    final Plane zPlane = new Plane(zUnitVector,-Z);
-    final SidedPlane minXPlane = new SidedPlane(maxX,0.0,0.0,xUnitVector,-minX);
-    final SidedPlane maxXPlane = new SidedPlane(minX,0.0,0.0,xUnitVector,-maxX);
-    surfacePoints = yPlane.findIntersections(planetModel,zPlane,minXPlane,maxXPlane);
-  }
-
-  @Override
-  protected GeoPoint[] getEdgePoints() {
-    return surfacePoints;
-  }
-  
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    for (final GeoPoint p : surfacePoints) {
-      if (p.isIdentical(x,y,z))
-        return true;
-    }
-    return false;
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    //System.err.println(this+" getrelationship with "+path);
-    final int insideRectangle = isShapeInsideArea(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some inside");
-      return OVERLAPS;
-    }
-
-    // Figure out if the entire XYZArea is contained by the shape.
-    final int insideShape = isAreaInsideShape(path);
-    if (insideShape == SOME_INSIDE) {
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
-      //System.err.println(" inside of each other");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      return WITHIN;
-    }
-    
-    if (insideShape == ALL_INSIDE) {
-      //System.err.println(" shape contains rectangle");
-      return CONTAINS;
-    }
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof XdYdZSolid))
-      return false;
-    XdYdZSolid other = (XdYdZSolid) o;
-    if (!super.equals(other) || surfacePoints.length != other.surfacePoints.length ) {
-      return false;
-    }
-    for (int i = 0; i < surfacePoints.length; i++) {
-      if (!surfacePoints[i].equals(other.surfacePoints[i]))
-        return false;
-    }
-    return true;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    for (final GeoPoint p : surfacePoints) {
-      result = 31 * result  + p.hashCode();
-    }
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    final StringBuilder sb = new StringBuilder();
-    for (final GeoPoint p : surfacePoints) {
-      sb.append(" ").append(p).append(" ");
-    }
-    return "XdYdZSolid: {planetmodel="+planetModel+", "+sb.toString()+"}";
-  }
-  
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXYZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXYZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXYZSolid.java
deleted file mode 100644
index 5a2a006..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXYZSolid.java
+++ /dev/null
@@ -1,216 +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.geo3d;
-
-/**
- * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in X.
- *
- * @lucene.internal
- */
-public class dXYZSolid extends BaseXYZSolid {
-
-  /** X plane */
-  protected final Plane xPlane;
-  /** Min-Y plane */
-  protected final SidedPlane minYPlane;
-  /** Max-Y plane */
-  protected final SidedPlane maxYPlane;
-  /** Min-Z plane */
-  protected final SidedPlane minZPlane;
-  /** Max-Z plane */
-  protected final SidedPlane maxZPlane;
-  
-  /** These are the edge points of the shape, which are defined to be at least one point on
-   * each surface area boundary.  In the case of a solid, this includes points which represent
-   * the intersection of XYZ bounding planes and the planet, as well as points representing
-   * the intersection of single bounding planes with the planet itself.
-   */
-  protected final GeoPoint[] edgePoints;
-
-  /** Notable points for XPlane */
-  protected final GeoPoint[] notableXPoints;
-
-  /**
-   * Sole constructor
-   *
-   *@param planetModel is the planet model.
-   *@param X is the X value.
-   *@param minY is the minimum Y value.
-   *@param maxY is the maximum Y value.
-   *@param minZ is the minimum Z value.
-   *@param maxZ is the maximum Z value.
-   */
-  public dXYZSolid(final PlanetModel planetModel,
-    final double X,
-    final double minY,
-    final double maxY,
-    final double minZ,
-    final double maxZ) {
-    super(planetModel);
-    // Argument checking
-    if (maxY - minY < Vector.MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("Y values in wrong order or identical");
-    if (maxZ - minZ < Vector.MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("Z values in wrong order or identical");
-
-    final double worldMinX = planetModel.getMinimumXValue();
-    final double worldMaxX = planetModel.getMaximumXValue();
-    
-    // Construct the planes
-    xPlane = new Plane(xUnitVector,-X);
-    minYPlane = new SidedPlane(0.0,maxY,0.0,yUnitVector,-minY);
-    maxYPlane = new SidedPlane(0.0,minY,0.0,yUnitVector,-maxY);
-    minZPlane = new SidedPlane(0.0,0.0,maxZ,zUnitVector,-minZ);
-    maxZPlane = new SidedPlane(0.0,0.0,minZ,zUnitVector,-maxZ);
-      
-    // We need at least one point on the planet surface for each manifestation of the shape.
-    // There can be up to 2 (on opposite sides of the world).  But we have to go through
-    // 4 combinations of adjacent planes in order to find out if any have 2 intersection solution.
-    // Typically, this requires 4 square root operations. 
-    final GeoPoint[] XminY = xPlane.findIntersections(planetModel,minYPlane,maxYPlane,minZPlane,maxZPlane);
-    final GeoPoint[] XmaxY = xPlane.findIntersections(planetModel,maxYPlane,minYPlane,minZPlane,maxZPlane);
-    final GeoPoint[] XminZ = xPlane.findIntersections(planetModel,minZPlane,maxZPlane,minYPlane,maxYPlane);
-    final GeoPoint[] XmaxZ = xPlane.findIntersections(planetModel,maxZPlane,minZPlane,minYPlane,maxYPlane);
-
-    notableXPoints = glueTogether(XminY, XmaxY, XminZ, XmaxZ);
-
-    // Now, compute the edge points.
-    // This is the trickiest part of setting up an XYZSolid.  We've computed intersections already, so
-    // we'll start there.  We know that at most there will be two disconnected shapes on the planet surface.
-    // But there's also a case where exactly one plane slices through the world, and none of the bounding plane
-    // intersections do.  Thus, if we don't find any of the edge intersection cases, we have to look for that last case.
-      
-    // We need to look at single-plane/world intersections.
-    // We detect these by looking at the world model and noting its x, y, and z bounds.
-    // For the single-dimension degenerate case, there's really only one plane that can possibly intersect the world.
-    // The cases we are looking for are when the four corner points for any given
-    // plane are all outside of the world, AND that plane intersects the world.
-    // There are four corner points all told; we must evaluate these WRT the planet surface.
-    final boolean XminYminZ = planetModel.pointOutside(X, minY, minZ);
-    final boolean XminYmaxZ = planetModel.pointOutside(X, minY, maxZ);
-    final boolean XmaxYminZ = planetModel.pointOutside(X, maxY, minZ);
-    final boolean XmaxYmaxZ = planetModel.pointOutside(X, maxY, maxZ);
-
-    final GeoPoint[] xEdges;
-    if (X - worldMinX >= -Vector.MINIMUM_RESOLUTION && X - worldMaxX <= Vector.MINIMUM_RESOLUTION &&
-      minY < 0.0 && maxY > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
-      XminYminZ && XminYmaxZ && XmaxYminZ && XmaxYmaxZ) {
-      // Find any point on the X plane that intersects the world
-      // First construct a perpendicular plane that will allow us to find a sample point.
-      // This plane is vertical and goes through the points (0,0,0) and (1,0,0)
-      // Then use it to compute a sample point.
-      final GeoPoint intPoint = xPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
-      if (intPoint != null) {
-        xEdges = new GeoPoint[]{intPoint};
-      } else {
-        xEdges = EMPTY_POINTS;
-      }
-    } else {
-      xEdges = EMPTY_POINTS;
-    }
-
-    this.edgePoints = glueTogether(XminY,XmaxY,XminZ,XmaxZ,xEdges);
-  }
-
-  @Override
-  protected GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-  
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return xPlane.evaluateIsZero(x, y, z) &&
-      minYPlane.isWithin(x, y, z) &&
-      maxYPlane.isWithin(x, y, z) &&
-      minZPlane.isWithin(x, y, z) &&
-      maxZPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    //System.err.println(this+" getrelationship with "+path);
-    final int insideRectangle = isShapeInsideArea(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some shape points inside area");
-      return OVERLAPS;
-    }
-
-    // Figure out if the entire XYZArea is contained by the shape.
-    final int insideShape = isAreaInsideShape(path);
-    if (insideShape == SOME_INSIDE) {
-      //System.err.println(" some area points inside shape");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
-      //System.err.println(" inside of each other");
-      return OVERLAPS;
-    }
-
-    // The entire locus of points in this shape is on a single plane, so we only need ot look for an intersection with that plane.
-    //System.err.println("xPlane = "+xPlane);
-    if (path.intersects(xPlane, notableXPoints, minYPlane, maxYPlane, minZPlane, maxZPlane)) {
-      //System.err.println(" edges intersect");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      //System.err.println(" shape points inside area");
-      return WITHIN;
-    }
-
-    if (insideShape == ALL_INSIDE) {
-      //System.err.println(" shape contains all area");
-      return CONTAINS;
-    }
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof dXYZSolid))
-      return false;
-    dXYZSolid other = (dXYZSolid) o;
-    if (!super.equals(other)) {
-      return false;
-    }
-    return other.xPlane.equals(xPlane) &&
-      other.minYPlane.equals(minYPlane) &&
-      other.maxYPlane.equals(maxYPlane) &&
-      other.minZPlane.equals(minZPlane) &&
-      other.maxZPlane.equals(maxZPlane);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result  + xPlane.hashCode();
-    result = 31 * result  + minYPlane.hashCode();
-    result = 31 * result  + maxYPlane.hashCode();
-    result = 31 * result  + minZPlane.hashCode();
-    result = 31 * result  + maxZPlane.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "dXYZSolid: {planetmodel="+planetModel+", xplane="+xPlane+", minYplane="+minYPlane+", maxYplane="+maxYPlane+", minZplane="+minZPlane+", maxZplane="+maxZPlane+"}";
-  }
-  
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXYdZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXYdZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXYdZSolid.java
deleted file mode 100644
index 96b3004..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXYdZSolid.java
+++ /dev/null
@@ -1,138 +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.geo3d;
-
-/**
- * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in X and Z.
- * This figure, in fact, represents either zero, one, or two points, so the
- * actual data stored is minimal.
- *
- * @lucene.internal
- */
-public class dXYdZSolid extends BaseXYZSolid {
-
-  /** The points in this figure on the planet surface; also doubles for edge points */
-  protected final GeoPoint[] surfacePoints;
-  
-  /**
-   * Sole constructor
-   *
-   *@param planetModel is the planet model.
-   *@param X is the X value.
-   *@param minY is the minimum Y value.
-   *@param maxY is the maximum Y value.
-   *@param Z is the Z value.
-   */
-  public dXYdZSolid(final PlanetModel planetModel,
-    final double X,
-    final double minY,
-    final double maxY,
-    final double Z) {
-    super(planetModel);
-    // Argument checking
-    if (maxY - minY < Vector.MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("Y values in wrong order or identical");
-
-    // Build the planes and intersect them.
-    final Plane xPlane = new Plane(xUnitVector,-X);
-    final Plane zPlane = new Plane(zUnitVector,-Z);
-    final SidedPlane minYPlane = new SidedPlane(0.0,maxY,0.0,yUnitVector,-minY);
-    final SidedPlane maxYPlane = new SidedPlane(0.0,minY,0.0,yUnitVector,-maxY);
-    surfacePoints = xPlane.findIntersections(planetModel,zPlane,minYPlane,maxYPlane);
-  }
-
-  @Override
-  protected GeoPoint[] getEdgePoints() {
-    return surfacePoints;
-  }
-  
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    for (final GeoPoint p : surfacePoints) {
-      if (p.isIdentical(x,y,z))
-        return true;
-    }
-    return false;
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    //System.err.println(this+" getrelationship with "+path);
-    final int insideRectangle = isShapeInsideArea(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some inside");
-      return OVERLAPS;
-    }
-
-    // Figure out if the entire XYZArea is contained by the shape.
-    final int insideShape = isAreaInsideShape(path);
-    if (insideShape == SOME_INSIDE) {
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
-      //System.err.println(" inside of each other");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      return WITHIN;
-    }
-    
-    if (insideShape == ALL_INSIDE) {
-      //System.err.println(" shape contains rectangle");
-      return CONTAINS;
-    }
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof dXYdZSolid))
-      return false;
-    dXYdZSolid other = (dXYdZSolid) o;
-    if (!super.equals(other) || surfacePoints.length != other.surfacePoints.length ) {
-      return false;
-    }
-    for (int i = 0; i < surfacePoints.length; i++) {
-      if (!surfacePoints[i].equals(other.surfacePoints[i]))
-        return false;
-    }
-    return true;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    for (final GeoPoint p : surfacePoints) {
-      result = 31 * result  + p.hashCode();
-    }
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    final StringBuilder sb = new StringBuilder();
-    for (final GeoPoint p : surfacePoints) {
-      sb.append(" ").append(p).append(" ");
-    }
-    return "dXYdZSolid: {planetmodel="+planetModel+", "+sb.toString()+"}";
-  }
-  
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXdYZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXdYZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXdYZSolid.java
deleted file mode 100644
index b58cd92..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXdYZSolid.java
+++ /dev/null
@@ -1,138 +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.geo3d;
-
-/**
- * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in X and Y.
- * This figure, in fact, represents either zero, one, or two points, so the
- * actual data stored is minimal.
- *
- * @lucene.internal
- */
-public class dXdYZSolid extends BaseXYZSolid {
-
-  /** The points in this figure on the planet surface; also doubles for edge points */
-  protected final GeoPoint[] surfacePoints;
-  
-  /**
-   * Sole constructor
-   *
-   *@param planetModel is the planet model.
-   *@param X is the X value.
-   *@param Y is the Y value.
-   *@param minZ is the minimum Z value.
-   *@param maxZ is the maximum Z value.
-   */
-  public dXdYZSolid(final PlanetModel planetModel,
-    final double X,
-    final double Y,
-    final double minZ,
-    final double maxZ) {
-    super(planetModel);
-    // Argument checking
-    if (maxZ - minZ < Vector.MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("Z values in wrong order or identical");
-
-    // Build the planes and intersect them.
-    final Plane xPlane = new Plane(xUnitVector,-X);
-    final Plane yPlane = new Plane(yUnitVector,-Y);
-    final SidedPlane minZPlane = new SidedPlane(0.0,0.0,maxZ,zUnitVector,-minZ);
-    final SidedPlane maxZPlane = new SidedPlane(0.0,0.0,minZ,zUnitVector,-maxZ);
-    surfacePoints = xPlane.findIntersections(planetModel,yPlane,minZPlane,maxZPlane);
-  }
-
-  @Override
-  protected GeoPoint[] getEdgePoints() {
-    return surfacePoints;
-  }
-  
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    for (final GeoPoint p : surfacePoints) {
-      if (p.isIdentical(x,y,z))
-        return true;
-    }
-    return false;
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    //System.err.println(this+" getrelationship with "+path);
-    final int insideRectangle = isShapeInsideArea(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some inside");
-      return OVERLAPS;
-    }
-
-    // Figure out if the entire XYZArea is contained by the shape.
-    final int insideShape = isAreaInsideShape(path);
-    if (insideShape == SOME_INSIDE) {
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
-      //System.err.println(" inside of each other");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      return WITHIN;
-    }
-    
-    if (insideShape == ALL_INSIDE) {
-      //System.err.println(" shape contains rectangle");
-      return CONTAINS;
-    }
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof dXdYZSolid))
-      return false;
-    dXdYZSolid other = (dXdYZSolid) o;
-    if (!super.equals(other) || surfacePoints.length != other.surfacePoints.length ) {
-      return false;
-    }
-    for (int i = 0; i < surfacePoints.length; i++) {
-      if (!surfacePoints[i].equals(other.surfacePoints[i]))
-        return false;
-    }
-    return true;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    for (final GeoPoint p : surfacePoints) {
-      result = 31 * result  + p.hashCode();
-    }
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    final StringBuilder sb = new StringBuilder();
-    for (final GeoPoint p : surfacePoints) {
-      sb.append(" ").append(p).append(" ");
-    }
-    return "dXdYZSolid: {planetmodel="+planetModel+", "+sb.toString()+"}";
-  }
-  
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXdYdZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXdYdZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXdYdZSolid.java
deleted file mode 100644
index b26cf63..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/dXdYdZSolid.java
+++ /dev/null
@@ -1,146 +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.geo3d;
-
-/**
- * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in all dimensions
- *
- * @lucene.internal
- */
-public class dXdYdZSolid extends BaseXYZSolid {
-
-  /** On surface? */
-  protected final boolean isOnSurface;
-  /** The point */
-  protected final GeoPoint thePoint;
-  
-  /** These are the edge points of the shape, which are defined to be at least one point on
-   * each surface area boundary.  In the case of a solid, this includes points which represent
-   * the intersection of XYZ bounding planes and the planet, as well as points representing
-   * the intersection of single bounding planes with the planet itself.
-   */
-  protected final GeoPoint[] edgePoints;
-
-  /** Empty array of {@link GeoPoint}. */
-  protected static final GeoPoint[] nullPoints = new GeoPoint[0];
-  
-  /**
-   * Sole constructor
-   *
-   *@param planetModel is the planet model.
-   *@param X is the X value.
-   *@param Y is the Y value.
-   *@param Z is the Z value.
-   */
-  public dXdYdZSolid(final PlanetModel planetModel,
-    final double X,
-    final double Y,
-    final double Z) {
-    super(planetModel);
-    isOnSurface = planetModel.pointOnSurface(X,Y,Z);
-    if (isOnSurface) {
-      thePoint = new GeoPoint(X,Y,Z);
-      edgePoints = new GeoPoint[]{thePoint};
-    } else {
-      thePoint = null;
-      edgePoints = nullPoints;
-    }
-  }
-
-  @Override
-  protected GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-  
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    if (!isOnSurface) {
-      return false;
-    }
-    return thePoint.isIdentical(x,y,z);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    if (!isOnSurface) {
-      return DISJOINT;
-    }
-    
-    //System.err.println(this+" getrelationship with "+path);
-    final int insideRectangle = isShapeInsideArea(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some shape points inside area");
-      return OVERLAPS;
-    }
-
-    // Figure out if the entire XYZArea is contained by the shape.
-    final int insideShape = isAreaInsideShape(path);
-    if (insideShape == SOME_INSIDE) {
-      //System.err.println(" some area points inside shape");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
-      //System.err.println(" inside of each other");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      //System.err.println(" shape inside area entirely");
-      return WITHIN;
-    }
-
-    if (insideShape == ALL_INSIDE) {
-      //System.err.println(" shape contains area entirely");
-      return CONTAINS;
-    }
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof dXdYdZSolid))
-      return false;
-    dXdYdZSolid other = (dXdYdZSolid) o;
-    if (!super.equals(other) ||
-      other.isOnSurface != isOnSurface) {
-      return false;
-    }
-    if (isOnSurface) {
-      return other.thePoint.equals(thePoint);
-    }
-    return true;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + (isOnSurface?1:0);
-    if (isOnSurface) {
-      result = 31 * result  + thePoint.hashCode();
-    }
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "dXdYdZSolid: {planetmodel="+planetModel+", isOnSurface="+isOnSurface+", thePoint="+thePoint+"}";
-  }
-  
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/package-info.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/package-info.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/package-info.java
deleted file mode 100644
index 2b6af74..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/package-info.java
+++ /dev/null
@@ -1,21 +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.
- */
-
-/**
- * Shapes implemented using 3D planar geometry.
- */
-package org.apache.lucene.geo3d;

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPoint.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPoint.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPoint.java
new file mode 100644
index 0000000..cd2c79a
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPoint.java
@@ -0,0 +1,114 @@
+/*
+ * 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.spatial3d;
+
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.FieldType;
+import org.apache.lucene.spatial3d.geom.GeoPoint;
+import org.apache.lucene.spatial3d.geom.GeoShape;
+import org.apache.lucene.spatial3d.geom.PlanetModel;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.util.BytesRef;
+import org.apache.lucene.util.NumericUtils;
+
+/**
+ * Add this to a document to index lat/lon or x/y/z point, indexed as a 3D point.
+ * Multiple values are allowed: just add multiple Geo3DPoint to the document with the
+ * same field name.
+ * <p>
+ * This field defines static factory methods for creating a shape query:
+ * <ul>
+ *   <li>{@link #newShapeQuery newShapeQuery()} for matching all points inside a specified shape
+ * </ul>
+ *
+ *  @lucene.experimental */
+public final class Geo3DPoint extends Field {
+
+  /** Indexing {@link FieldType}. */
+  public static final FieldType TYPE = new FieldType();
+  static {
+    TYPE.setDimensions(3, Integer.BYTES);
+    TYPE.freeze();
+  }
+
+  /** 
+   * Creates a new Geo3DPoint field with the specified lat, lon (in radians).
+   *
+   * @throws IllegalArgumentException if the field name is null or lat or lon are out of bounds
+   */
+  public Geo3DPoint(String name, double lat, double lon) {
+    super(name, TYPE);
+    // Translate lat/lon to x,y,z:
+    final GeoPoint point = new GeoPoint(PlanetModel.WGS84, lat, lon);
+    fillFieldsData(point.x, point.y, point.z);
+  }
+
+  /** 
+   * Creates a new Geo3DPoint field with the specified x,y,z.
+   *
+   * @throws IllegalArgumentException if the field name is null or lat or lon are out of bounds
+   */
+  public Geo3DPoint(String name, double x, double y, double z) {
+    super(name, TYPE);
+    fillFieldsData(x, y, z);
+  }
+
+  private void fillFieldsData(double x, double y, double z) {
+    byte[] bytes = new byte[12];
+    encodeDimension(x, bytes, 0);
+    encodeDimension(y, bytes, Integer.BYTES);
+    encodeDimension(z, bytes, 2*Integer.BYTES);
+    fieldsData = new BytesRef(bytes);
+  }
+
+  // public helper methods (e.g. for queries)
+  
+  /** Encode single dimension */
+  public static void encodeDimension(double value, byte bytes[], int offset) {
+    NumericUtils.intToSortableBytes(Geo3DUtil.encodeValue(PlanetModel.WGS84.getMaximumMagnitude(), value), bytes, offset);
+  }
+  
+  /** Decode single dimension */
+  public static double decodeDimension(byte value[], int offset) {
+    return Geo3DUtil.decodeValueCenter(PlanetModel.WGS84.getMaximumMagnitude(), NumericUtils.sortableBytesToInt(value, offset));
+  }
+
+  /** Returns a query matching all points inside the provided shape.
+   * 
+   * @param field field name. must not be {@code null}.
+   * @param shape Which {@link GeoShape} to match
+   */
+  public static Query newShapeQuery(String field, GeoShape shape) {
+    return new PointInGeo3DShapeQuery(field, shape);
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder result = new StringBuilder();
+    result.append(getClass().getSimpleName());
+    result.append(" <");
+    result.append(name);
+    result.append(':');
+
+    BytesRef bytes = (BytesRef) fieldsData;
+    result.append(" x=" + decodeDimension(bytes.bytes, bytes.offset));
+    result.append(" y=" + decodeDimension(bytes.bytes, bytes.offset + Integer.BYTES));
+    result.append(" z=" + decodeDimension(bytes.bytes, bytes.offset + 2*Integer.BYTES));
+    result.append('>');
+    return result.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DUtil.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DUtil.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DUtil.java
new file mode 100644
index 0000000..0a0bf30
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DUtil.java
@@ -0,0 +1,59 @@
+/*
+ * 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.spatial3d;
+
+class Geo3DUtil {
+
+  /** Clips the incoming value to the allowed min/max range before encoding, instead of throwing an exception. */
+  public static int encodeValueLenient(double planetMax, double x) {
+    if (x > planetMax) {
+      x = planetMax;
+    } else if (x < -planetMax) {
+      x = -planetMax;
+    }
+    return encodeValue(planetMax, x);
+  }
+
+  public static int encodeValue(double planetMax, double x) {
+    if (x > planetMax) {
+      throw new IllegalArgumentException("value=" + x + " is out-of-bounds (greater than planetMax=" + planetMax + ")");
+    }
+    if (x < -planetMax) {
+      throw new IllegalArgumentException("value=" + x + " is out-of-bounds (less than than -planetMax=" + -planetMax + ")");
+    }
+    long y = Math.round (x * (Integer.MAX_VALUE / planetMax));
+    assert y >= Integer.MIN_VALUE;
+    assert y <= Integer.MAX_VALUE;
+
+    return (int) y;
+  }
+
+  /** Center decode */
+  public static double decodeValueCenter(double planetMax, int x) {
+    return x * (planetMax / Integer.MAX_VALUE);
+  }
+
+  /** More negative decode, at bottom of cell */
+  public static double decodeValueMin(double planetMax, int x) {
+    return (((double)x) - 0.5) * (planetMax / Integer.MAX_VALUE);
+  }
+  
+  /** More positive decode, at top of cell  */
+  public static double decodeValueMax(double planetMax, int x) {
+    return (((double)x) + 0.5) * (planetMax / Integer.MAX_VALUE);
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/PointInGeo3DShapeQuery.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/PointInGeo3DShapeQuery.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/PointInGeo3DShapeQuery.java
new file mode 100644
index 0000000..9df8752
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/PointInGeo3DShapeQuery.java
@@ -0,0 +1,215 @@
+/*
+ * 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.spatial3d;
+
+import java.io.IOException;
+
+import org.apache.lucene.spatial3d.geom.BasePlanetObject;
+import org.apache.lucene.spatial3d.geom.GeoArea;
+import org.apache.lucene.spatial3d.geom.GeoAreaFactory;
+import org.apache.lucene.spatial3d.geom.GeoShape;
+import org.apache.lucene.spatial3d.geom.PlanetModel;
+import org.apache.lucene.index.PointValues.IntersectVisitor;
+import org.apache.lucene.index.PointValues;
+import org.apache.lucene.index.PointValues.Relation;
+import org.apache.lucene.index.LeafReader;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.search.ConstantScoreScorer;
+import org.apache.lucene.search.ConstantScoreWeight;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.Scorer;
+import org.apache.lucene.search.Weight;
+import org.apache.lucene.util.DocIdSetBuilder;
+import org.apache.lucene.util.NumericUtils;
+
+/** Finds all previously indexed points that fall within the specified polygon.
+ *
+ * <p>The field must be indexed using {@link Geo3DPoint}.
+ *
+ * @lucene.experimental */
+
+class PointInGeo3DShapeQuery extends Query {
+  final String field;
+  final GeoShape shape;
+
+  /** The lats/lons must be clockwise or counter-clockwise. */
+  public PointInGeo3DShapeQuery(String field, GeoShape shape) {
+    this.field = field;
+    this.shape = shape;
+
+    if (shape instanceof BasePlanetObject) {
+      BasePlanetObject planetObject = (BasePlanetObject) shape;
+      if (planetObject.getPlanetModel().equals(PlanetModel.WGS84) == false) {
+        throw new IllegalArgumentException("this qurey requires PlanetModel.WGS84, but got: " + planetObject.getPlanetModel());
+      }
+    }
+  }
+
+  @Override
+  public Weight createWeight(IndexSearcher searcher, boolean needsScores) throws IOException {
+
+    // I don't use RandomAccessWeight here: it's no good to approximate with "match all docs"; this is an inverted structure and should be
+    // used in the first pass:
+
+    return new ConstantScoreWeight(this) {
+
+      @Override
+      public Scorer scorer(LeafReaderContext context) throws IOException {
+        LeafReader reader = context.reader();
+        PointValues values = reader.getPointValues();
+        if (values == null) {
+          return null;
+        }
+
+        /*
+        XYZBounds bounds = new XYZBounds();
+        shape.getBounds(bounds);
+
+        final double planetMax = planetModel.getMaximumMagnitude();
+        if (planetMax != treeDV.planetMax) {
+          throw new IllegalStateException(planetModel + " is not the same one used during indexing: planetMax=" + planetMax + " vs indexing planetMax=" + treeDV.planetMax);
+        }
+        */
+
+        /*
+        GeoArea xyzSolid = GeoAreaFactory.makeGeoArea(planetModel,
+                                                      bounds.getMinimumX(),
+                                                      bounds.getMaximumX(),
+                                                      bounds.getMinimumY(),
+                                                      bounds.getMaximumY(),
+                                                      bounds.getMinimumZ(),
+                                                      bounds.getMaximumZ());
+
+        assert xyzSolid.getRelationship(shape) == GeoArea.WITHIN || xyzSolid.getRelationship(shape) == GeoArea.OVERLAPS: "expected WITHIN (1) or OVERLAPS (2) but got " + xyzSolid.getRelationship(shape) + "; shape="+shape+"; XYZSolid="+xyzSolid;
+        */
+
+        double planetMax = PlanetModel.WGS84.getMaximumMagnitude();
+
+        DocIdSetBuilder result = new DocIdSetBuilder(reader.maxDoc());
+
+        values.intersect(field,
+                         new IntersectVisitor() {
+
+                           @Override
+                           public void visit(int docID) {
+                             result.add(docID);
+                           }
+
+                           @Override
+                           public void visit(int docID, byte[] packedValue) {
+                             assert packedValue.length == 12;
+                             double x = Geo3DPoint.decodeDimension(packedValue, 0);
+                             double y = Geo3DPoint.decodeDimension(packedValue, Integer.BYTES);
+                             double z = Geo3DPoint.decodeDimension(packedValue, 2 * Integer.BYTES);
+                             if (shape.isWithin(x, y, z)) {
+                               result.add(docID);
+                             }
+                           }
+
+                           @Override
+                           public Relation compare(byte[] minPackedValue, byte[] maxPackedValue) {
+                             // Because the dimensional format operates in quantized (64 bit -> 32 bit) space, and the cell bounds
+                             // here are inclusive, we need to extend the bounds to the largest un-quantized values that
+                             // could quantize into these bounds.  The encoding (Geo3DUtil.encodeValue) does
+                             // a Math.round from double to long, so e.g. 1.4 -> 1, and -1.4 -> -1:
+                             double xMin = Geo3DUtil.decodeValueMin(planetMax, NumericUtils.sortableBytesToInt(minPackedValue, 0));
+                             double xMax = Geo3DUtil.decodeValueMax(planetMax, NumericUtils.sortableBytesToInt(maxPackedValue, 0));
+                             double yMin = Geo3DUtil.decodeValueMin(planetMax, NumericUtils.sortableBytesToInt(minPackedValue, 1 * Integer.BYTES));
+                             double yMax = Geo3DUtil.decodeValueMax(planetMax, NumericUtils.sortableBytesToInt(maxPackedValue, 1 * Integer.BYTES));
+                             double zMin = Geo3DUtil.decodeValueMin(planetMax, NumericUtils.sortableBytesToInt(minPackedValue, 2 * Integer.BYTES));
+                             double zMax = Geo3DUtil.decodeValueMax(planetMax, NumericUtils.sortableBytesToInt(maxPackedValue, 2 * Integer.BYTES));
+
+                             //System.out.println("  compare: x=" + cellXMin + "-" + cellXMax + " y=" + cellYMin + "-" + cellYMax + " z=" + cellZMin + "-" + cellZMax);
+                             assert xMin <= xMax;
+                             assert yMin <= yMax;
+                             assert zMin <= zMax;
+
+                             GeoArea xyzSolid = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84, xMin, xMax, yMin, yMax, zMin, zMax);
+
+                             switch(xyzSolid.getRelationship(shape)) {
+                             case GeoArea.CONTAINS:
+                               // Shape fully contains the cell
+                               //System.out.println("    inside");
+                               return Relation.CELL_INSIDE_QUERY;
+                             case GeoArea.OVERLAPS:
+                               // They do overlap but neither contains the other:
+                               //System.out.println("    crosses1");
+                               return Relation.CELL_CROSSES_QUERY;
+                             case GeoArea.WITHIN:
+                               // Cell fully contains the shape:
+                               //System.out.println("    crosses2");
+                               // return Relation.SHAPE_INSIDE_CELL;
+                               return Relation.CELL_CROSSES_QUERY;
+                             case GeoArea.DISJOINT:
+                               // They do not overlap at all
+                               //System.out.println("    outside");
+                               return Relation.CELL_OUTSIDE_QUERY;
+                             default:
+                               assert false;
+                               return Relation.CELL_CROSSES_QUERY;
+                             }
+                           }
+                         });
+
+        return new ConstantScoreScorer(this, score(), result.build().iterator());
+      }
+    };
+  }
+
+  public String getField() {
+    return field;
+  }
+
+  public GeoShape getShape() {
+    return shape;
+  }
+
+  @Override
+  @SuppressWarnings({"unchecked","rawtypes"})
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+    if (!super.equals(o)) return false;
+
+    PointInGeo3DShapeQuery that = (PointInGeo3DShapeQuery) o;
+
+    return shape.equals(that.shape);
+  }
+
+  @Override
+  public final int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + shape.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString(String field) {
+    final StringBuilder sb = new StringBuilder();
+    sb.append(getClass().getSimpleName());
+    sb.append(':');
+    if (this.field.equals(field) == false) {
+      sb.append(" field=");
+      sb.append(this.field);
+      sb.append(':');
+    }
+    sb.append(" Shape: ");
+    sb.append(shape);
+    return sb.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/ArcDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/ArcDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/ArcDistance.java
new file mode 100644
index 0000000..bb60be0
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/ArcDistance.java
@@ -0,0 +1,56 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Arc distance computation style.
+ *
+ * @lucene.experimental
+ */
+public class ArcDistance implements DistanceStyle {
+  
+  /** An instance of the ArcDistance DistanceStyle. */
+  public final static ArcDistance INSTANCE = new ArcDistance();
+  
+  /** Constructor.
+   */
+  public ArcDistance() {
+  }
+  
+  @Override
+  public double computeDistance(final GeoPoint point1, final GeoPoint point2) {
+    return point1.arcDistance(point2);
+  }
+  
+  @Override
+  public double computeDistance(final GeoPoint point1, final double x2, final double y2, final double z2) {
+    return point1.arcDistance(x2,y2,z2);
+  }
+
+  @Override
+  public double computeDistance(final PlanetModel planetModel, final Plane plane, final GeoPoint point, final Membership... bounds) {
+    return plane.arcDistance(planetModel, point, bounds);
+  }
+  
+  @Override
+  public double computeDistance(final PlanetModel planetModel, final Plane plane, final double x, final double y, final double z, final Membership... bounds) {
+    return plane.arcDistance(planetModel, x,y,z, bounds);
+  }
+
+}
+
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/BasePlanetObject.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/BasePlanetObject.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/BasePlanetObject.java
new file mode 100644
index 0000000..5cd5acc
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/BasePlanetObject.java
@@ -0,0 +1,57 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * All Geo3D shapes can derive from this base class, which furnishes
+ * some common code
+ *
+ * @lucene.internal
+ */
+public abstract class BasePlanetObject {
+
+  /** This is the planet model embedded in all objects derived from this
+   * class. */
+  protected final PlanetModel planetModel;
+  
+  /** Constructor creating class instance given a planet model.
+   * @param planetModel is the planet model.
+   */
+  public BasePlanetObject(final PlanetModel planetModel) {
+    this.planetModel = planetModel;
+  }
+
+  /** Returns the {@link PlanetModel} provided when this shape was created. */
+  public PlanetModel getPlanetModel() {
+    return planetModel;
+  }
+  
+  @Override
+  public int hashCode() {
+    return planetModel.hashCode();
+  }
+  
+  @Override
+  public boolean equals(final Object o) {
+    if (!(o instanceof BasePlanetObject))
+      return false;
+    return planetModel.equals(((BasePlanetObject)o).planetModel);
+  }
+}
+
+
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/BaseXYZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/BaseXYZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/BaseXYZSolid.java
new file mode 100644
index 0000000..16b52cc
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/BaseXYZSolid.java
@@ -0,0 +1,167 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Base class of a family of 3D rectangles, bounded on six sides by X,Y,Z limits
+ *
+ * @lucene.internal
+ */
+public abstract class BaseXYZSolid extends BasePlanetObject implements XYZSolid {
+
+  /** Unit vector in x */
+  protected static final Vector xUnitVector = new Vector(1.0, 0.0, 0.0);
+  /** Unit vector in y */
+  protected static final Vector yUnitVector = new Vector(0.0, 1.0, 0.0);
+  /** Unit vector in z */
+  protected static final Vector zUnitVector = new Vector(0.0, 0.0, 1.0);
+  
+  /** Vertical plane normal to x unit vector passing through origin */
+  protected static final Plane xVerticalPlane = new Plane(0.0, 1.0, 0.0, 0.0);
+  /** Vertical plane normal to y unit vector passing through origin */
+  protected static final Plane yVerticalPlane = new Plane(1.0, 0.0, 0.0, 0.0);
+
+  /** Empty point vector */
+  protected static final GeoPoint[] EMPTY_POINTS = new GeoPoint[0];
+  
+  /**
+   * Base solid constructor.
+   *@param planetModel is the planet model.
+   */
+  public BaseXYZSolid(final PlanetModel planetModel) {
+    super(planetModel);
+  }
+  
+  /** Construct a single array from a number of individual arrays.
+   * @param pointArrays is the array of point arrays.
+   * @return the single unified array.
+   */
+  protected static GeoPoint[] glueTogether(final GeoPoint[]... pointArrays) {
+    int count = 0;
+    for (final GeoPoint[] pointArray : pointArrays) {
+      count += pointArray.length;
+    }
+    final GeoPoint[] rval = new GeoPoint[count];
+    count = 0;
+    for (final GeoPoint[] pointArray : pointArrays) {
+      for (final GeoPoint point : pointArray) {
+        rval[count++] = point;
+      }
+    }
+    return rval;
+  }
+  
+  @Override
+  public boolean isWithin(final Vector point) {
+    return isWithin(point.x, point.y, point.z);
+  }
+  
+  @Override
+  public abstract boolean isWithin(final double x, final double y, final double z);
+  
+  // Signals for relationship of edge points to shape
+  
+  /** All edgepoints inside shape */
+  protected final static int ALL_INSIDE = 0;
+  /** Some edgepoints inside shape */
+  protected final static int SOME_INSIDE = 1;
+  /** No edgepoints inside shape */
+  protected final static int NONE_INSIDE = 2;
+  /** No edgepoints at all (means a shape that is the whole world) */
+  protected final static int NO_EDGEPOINTS = 3;
+
+  /** Determine the relationship between this area and the provided
+   * shape's edgepoints.
+   *@param path is the shape.
+   *@return the relationship.
+   */
+  protected int isShapeInsideArea(final GeoShape path) {
+    final GeoPoint[] pathPoints = path.getEdgePoints();
+    if (pathPoints.length == 0)
+      return NO_EDGEPOINTS;
+    boolean foundOutside = false;
+    boolean foundInside = false;
+    for (final GeoPoint p : pathPoints) {
+      if (isWithin(p)) {
+        foundInside = true;
+      } else {
+        foundOutside = true;
+      }
+      if (foundInside && foundOutside) {
+        return SOME_INSIDE;
+      }
+    }
+    if (!foundInside && !foundOutside)
+      return NONE_INSIDE;
+    if (foundInside && !foundOutside)
+      return ALL_INSIDE;
+    if (foundOutside && !foundInside)
+      return NONE_INSIDE;
+    return SOME_INSIDE;
+  }
+
+  /** Determine the relationship between a shape and this area's
+   * edgepoints.
+   *@param path is the shape.
+   *@return the relationship.
+   */
+  protected int isAreaInsideShape(final GeoShape path) {
+    final GeoPoint[] edgePoints = getEdgePoints();
+    if (edgePoints.length == 0) {
+      return NO_EDGEPOINTS;
+    }
+    boolean foundOutside = false;
+    boolean foundInside = false;
+    for (final GeoPoint p : edgePoints) {
+      if (path.isWithin(p)) {
+        foundInside = true;
+      } else {
+        foundOutside = true;
+      }
+      if (foundInside && foundOutside) {
+        return SOME_INSIDE;
+      }
+    }
+    if (!foundInside && !foundOutside)
+      return NONE_INSIDE;
+    if (foundInside && !foundOutside)
+      return ALL_INSIDE;
+    if (foundOutside && !foundInside)
+      return NONE_INSIDE;
+    return SOME_INSIDE;
+  }
+
+  /** Get the edge points for this shape.
+   *@return the edge points.
+   */
+  protected abstract GeoPoint[] getEdgePoints();
+  
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof BaseXYZSolid))
+      return false;
+    BaseXYZSolid other = (BaseXYZSolid) o;
+    return super.equals(other);
+  }
+
+  @Override
+  public int hashCode() {
+    return super.hashCode();
+  }
+
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Bounds.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Bounds.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Bounds.java
new file mode 100755
index 0000000..4f7c663
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Bounds.java
@@ -0,0 +1,113 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * An interface for accumulating bounds information.
+ * The bounds object is initially empty.  Bounding points
+ * are then applied by supplying (x,y,z) tuples.  It is also
+ * possible to indicate the following edge cases:
+ * (1) No longitude bound possible
+ * (2) No upper latitude bound possible
+ * (3) No lower latitude bound possible
+ * When any of these have been applied, further application of
+ * points cannot override that decision.
+ *
+ * @lucene.experimental
+ */
+public interface Bounds {
+
+  /** Add a general plane to the bounds description.
+   *@param planetModel is the planet model.
+   *@param plane is the plane.
+   *@param bounds are the membership bounds for points along the arc.
+   */
+  public Bounds addPlane(final PlanetModel planetModel, final Plane plane, final Membership... bounds);
+  
+  /** Add a horizontal plane to the bounds description.
+   * This method should EITHER use the supplied latitude, OR use the supplied
+   * plane, depending on what is most efficient.
+   *@param planetModel is the planet model.
+   *@param latitude is the latitude.
+   *@param horizontalPlane is the plane.
+   *@param bounds are the constraints on the plane.
+   *@return updated Bounds object.
+   */
+  public Bounds addHorizontalPlane(final PlanetModel planetModel,
+    final double latitude,
+    final Plane horizontalPlane,
+    final Membership... bounds);
+    
+  /** Add a vertical plane to the bounds description.
+   * This method should EITHER use the supplied longitude, OR use the supplied
+   * plane, depending on what is most efficient.
+   *@param planetModel is the planet model.
+   *@param longitude is the longitude.
+   *@param verticalPlane is the plane.
+   *@param bounds are the constraints on the plane.
+   *@return updated Bounds object.
+   */
+  public Bounds addVerticalPlane(final PlanetModel planetModel,
+    final double longitude,
+    final Plane verticalPlane,
+    final Membership... bounds);
+
+  /** Add a single point.
+   *@param point is the point.
+   *@return the updated Bounds object.
+   */
+  public Bounds addPoint(final GeoPoint point);
+
+  /** Add an X value.
+   *@param point is the point to take the x value from.
+   *@return the updated object.
+   */
+  public Bounds addXValue(final GeoPoint point);
+
+  /** Add a Y value.
+   *@param point is the point to take the y value from.
+   *@return the updated object.
+   */
+  public Bounds addYValue(final GeoPoint point);
+
+  /** Add a Z value.
+   *@param point is the point to take the z value from.
+   *@return the updated object.
+   */
+  public Bounds addZValue(final GeoPoint point);
+  
+  /** Signal that the shape exceeds Math.PI in longitude.
+   *@return the updated Bounds object.
+   */
+  public Bounds isWide();
+  
+  /** Signal that there is no longitude bound.
+   *@return the updated Bounds object.
+   */
+  public Bounds noLongitudeBound();
+
+  /** Signal that there is no top latitude bound.
+   *@return the updated Bounds object.
+   */
+  public Bounds noTopLatitudeBound();
+
+  /** Signal that there is no bottom latitude bound.
+   *@return the updated Bounds object.
+   */
+  public Bounds noBottomLatitudeBound();
+  
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/DistanceStyle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/DistanceStyle.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/DistanceStyle.java
new file mode 100644
index 0000000..8c8658d
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/DistanceStyle.java
@@ -0,0 +1,83 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Distance computation styles, supporting various ways of computing
+ * distance to shapes.
+ *
+ * @lucene.experimental
+ */
+public interface DistanceStyle {
+
+  // convenient access to built-in styles:
+
+  /** Arc distance calculator */
+  public static final ArcDistance ARC = ArcDistance.INSTANCE;
+  /** Linear distance calculator */
+  public static final LinearDistance LINEAR = LinearDistance.INSTANCE;
+  /** Linear distance squared calculator */
+  public static final LinearSquaredDistance LINEAR_SQUARED = LinearSquaredDistance.INSTANCE;
+  /** Normal distance calculator */
+  public static final NormalDistance NORMAL = NormalDistance.INSTANCE;
+  /** Normal distance squared calculator */
+  public static final NormalSquaredDistance NORMAL_SQUARED = NormalSquaredDistance.INSTANCE;
+
+  /** Compute the distance from a point to another point.
+   * @param point1 Starting point
+   * @param point2 Final point
+   * @return the distance
+   */
+  public default double computeDistance(final GeoPoint point1, final GeoPoint point2) {
+    return computeDistance(point1, point2.x, point2.y, point2.z);
+  }
+  
+  /** Compute the distance from a point to another point.
+   * @param point1 Starting point
+   * @param x2 Final point x
+   * @param y2 Final point y
+   * @param z2 Final point z
+   * @return the distance
+   */
+  public double computeDistance(final GeoPoint point1, final double x2, final double y2, final double z2);
+
+  /** Compute the distance from a plane to a point.
+   * @param planetModel The planet model
+   * @param plane The plane
+   * @param point The point
+   * @param bounds are the plane bounds
+   * @return the distance
+   */
+  public default double computeDistance(final PlanetModel planetModel, final Plane plane, final GeoPoint point,
+                                        final Membership... bounds) {
+    return computeDistance(planetModel, plane, point.x, point.y, point.z, bounds);
+  }
+  
+  /** Compute the distance from a plane to a point.
+   * @param planetModel The planet model
+   * @param plane The plane
+   * @param x The point x
+   * @param y The point y
+   * @param z The point z
+   * @param bounds are the plane bounds
+   * @return the distance
+   */
+  public double computeDistance(final PlanetModel planetModel, final Plane plane, final double x, final double y, final double z, final Membership... bounds);
+
+}
+
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoArea.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoArea.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoArea.java
new file mode 100755
index 0000000..5a6db0d
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoArea.java
@@ -0,0 +1,67 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * A GeoArea represents a standard 2-D breakdown of a part of sphere.  It can
+ * be bounded in latitude, or bounded in both latitude and longitude, or not
+ * bounded at all.  The purpose of the interface is to describe bounding shapes used for
+ * computation of geo hashes.
+ *
+ * @lucene.experimental
+ */
+public interface GeoArea extends Membership {
+  // Since we don't know what each GeoArea's constraints are,
+  // we put the onus on the GeoArea implementation to do the right thing.
+  // This will, of course, rely heavily on methods provided by
+  // the underlying GeoShape class.
+
+  // Relationship values for "getRelationship()"
+  
+  /** The referenced shape CONTAINS this area */
+  public static final int CONTAINS = 0;
+  /** The referenced shape IS WITHIN this area */
+  public static final int WITHIN = 1;
+  /** The referenced shape OVERLAPS this area */
+  public static final int OVERLAPS = 2;
+  /** The referenced shape has no relation to this area */
+  public static final int DISJOINT = 3;
+
+  /**
+   * Find the spatial relationship between a shape and the current geo area.
+   * Note: return value is how the GeoShape relates to the GeoArea, not the
+   * other way around. For example, if this GeoArea is entirely within the
+   * shape, then CONTAINS should be returned.  If the shape is entirely enclosed
+   * by this GeoArea, then WITHIN should be returned.
+   *
+   * It is permissible to return OVERLAPS instead of WITHIN if the shape
+   * intersects with the area at even a single point.  So, a circle inscribed in
+   * a rectangle could return either OVERLAPS or WITHIN, depending on
+   * implementation.  It is not permissible to return CONTAINS or DISJOINT
+   * in this circumstance, however.
+   *
+   * Similarly, it is permissible to return OVERLAPS instead of CONTAINS
+   * under conditions where the shape consists of multiple independent overlapping
+   * subshapes, and the area overlaps one of the subshapes.  It is not permissible
+   * to return WITHIN or DISJOINT in this circumstance, however.
+   *
+   * @param shape is the shape to consider.
+   * @return the relationship, from the perspective of the shape.
+   */
+  public int getRelationship(GeoShape shape);
+}
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoAreaFactory.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoAreaFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoAreaFactory.java
new file mode 100755
index 0000000..0c3caa9
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoAreaFactory.java
@@ -0,0 +1,55 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Factory for {@link GeoArea}.
+ *
+ * @lucene.experimental
+ */
+public class GeoAreaFactory {
+  private GeoAreaFactory() {
+  }
+
+  /**
+   * Create a GeoArea of the right kind given the specified bounds.
+   * @param planetModel is the planet model
+   * @param topLat    is the top latitude
+   * @param bottomLat is the bottom latitude
+   * @param leftLon   is the left longitude
+   * @param rightLon  is the right longitude
+   * @return a GeoArea corresponding to what was specified.
+   */
+  public static GeoArea makeGeoArea(final PlanetModel planetModel, final double topLat, final double bottomLat, final double leftLon, final double rightLon) {
+    return GeoBBoxFactory.makeGeoBBox(planetModel, topLat, bottomLat, leftLon, rightLon);
+  }
+
+  /**
+   * Create a GeoArea of the right kind given (x,y,z) bounds.
+   * @param planetModel is the planet model
+   * @param minX is the min X boundary
+   * @param maxX is the max X boundary
+   * @param minY is the min Y boundary
+   * @param maxY is the max Y boundary
+   * @param minZ is the min Z boundary
+   * @param maxZ is the max Z boundary
+   */
+  public static GeoArea makeGeoArea(final PlanetModel planetModel, final double minX, final double maxX, final double minY, final double maxY, final double minZ, final double maxZ) {
+    return XYZSolidFactory.makeXYZSolid(planetModel, minX, maxX, minY, maxY, minZ, maxZ);
+  }
+  
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBBox.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBBox.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBBox.java
new file mode 100755
index 0000000..0ae2425
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoBBox.java
@@ -0,0 +1,36 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * All bounding box shapes have this interface in common.
+ * This describes methods that bounding boxes have above and beyond
+ * GeoMembershipShape's.
+ *
+ * @lucene.experimental
+ */
+public interface GeoBBox extends GeoMembershipShape, GeoSizeable, GeoArea {
+
+  /**
+   * Expand box by specified angle.
+   *
+   * @param angle is the angle amount to expand the GeoBBox by.
+   * @return a new GeoBBox.
+   */
+  public GeoBBox expand(double angle);
+
+}


[29/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 3a31a8c)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoSouthRectangle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoSouthRectangle.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoSouthRectangle.java
deleted file mode 100644
index eb6526b..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoSouthRectangle.java
+++ /dev/null
@@ -1,259 +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.geo3d;
-
-/**
- * Bounding box limited on three sides (top lat, left lon, right lon).  The
- * other corner is the south pole.
- * The left-right maximum extent for this shape is PI; for anything larger, use
- * {@link GeoWideSouthRectangle}.
- *
- * @lucene.internal
- */
-public class GeoSouthRectangle extends GeoBaseBBox {
-  /** The top latitude of the rect */
-  protected final double topLat;
-  /** The left longitude of the rect */
-  protected final double leftLon;
-  /** The right longitude of the rect */
-  protected final double rightLon;
-  /** The cosine of a middle latitude */
-  protected final double cosMiddleLat;
-  /** The upper left hand corner of the rectangle */
-  protected final GeoPoint ULHC;
-  /** The upper right hand corner of the rectangle */
-  protected final GeoPoint URHC;
-
-  /** The top plane */
-  protected final SidedPlane topPlane;
-  /** The left plane */
-  protected final SidedPlane leftPlane;
-  /** The right plane */
-  protected final SidedPlane rightPlane;
-
-  /** Notable points for the top plane */
-  protected final GeoPoint[] topPlanePoints;
-  /** Notable points for the left plane */
-  protected final GeoPoint[] leftPlanePoints;
-  /** Notable points for the right plane */
-  protected final GeoPoint[] rightPlanePoints;
-
-  /** The center point */
-  protected final GeoPoint centerPoint;
-
-  /** A point on the edge */
-  protected final GeoPoint[] edgePoints;
-
-  /**
-   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
-   *@param planetModel is the planet model.
-   *@param topLat is the top latitude.
-   *@param leftLon is the left longitude.
-   *@param rightLon is the right longitude.
-   */
-  public GeoSouthRectangle(final PlanetModel planetModel, final double topLat, final double leftLon, double rightLon) {
-    super(planetModel);
-    // Argument checking
-    if (topLat > Math.PI * 0.5 || topLat < -Math.PI * 0.5)
-      throw new IllegalArgumentException("Top latitude out of range");
-    if (leftLon < -Math.PI || leftLon > Math.PI)
-      throw new IllegalArgumentException("Left longitude out of range");
-    if (rightLon < -Math.PI || rightLon > Math.PI)
-      throw new IllegalArgumentException("Right longitude out of range");
-    double extent = rightLon - leftLon;
-    if (extent < 0.0) {
-      extent += 2.0 * Math.PI;
-    }
-    if (extent > Math.PI)
-      throw new IllegalArgumentException("Width of rectangle too great");
-
-    this.topLat = topLat;
-    this.leftLon = leftLon;
-    this.rightLon = rightLon;
-
-    final double sinTopLat = Math.sin(topLat);
-    final double cosTopLat = Math.cos(topLat);
-    final double sinLeftLon = Math.sin(leftLon);
-    final double cosLeftLon = Math.cos(leftLon);
-    final double sinRightLon = Math.sin(rightLon);
-    final double cosRightLon = Math.cos(rightLon);
-
-    // Now build the four points
-    this.ULHC = new GeoPoint(planetModel, sinTopLat, sinLeftLon, cosTopLat, cosLeftLon, topLat, leftLon);
-    this.URHC = new GeoPoint(planetModel, sinTopLat, sinRightLon, cosTopLat, cosRightLon, topLat, rightLon);
-
-    final double middleLat = (topLat - Math.PI * 0.5) * 0.5;
-    final double sinMiddleLat = Math.sin(middleLat);
-    this.cosMiddleLat = Math.cos(middleLat);
-    // Normalize
-    while (leftLon > rightLon) {
-      rightLon += Math.PI * 2.0;
-    }
-    final double middleLon = (leftLon + rightLon) * 0.5;
-    final double sinMiddleLon = Math.sin(middleLon);
-    final double cosMiddleLon = Math.cos(middleLon);
-
-    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinMiddleLon, cosMiddleLat, cosMiddleLon);
-
-    this.topPlane = new SidedPlane(centerPoint, planetModel, sinTopLat);
-    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
-    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
-
-    this.topPlanePoints = new GeoPoint[]{ULHC, URHC};
-    this.leftPlanePoints = new GeoPoint[]{ULHC, planetModel.SOUTH_POLE};
-    this.rightPlanePoints = new GeoPoint[]{URHC, planetModel.SOUTH_POLE};
-    
-    this.edgePoints = new GeoPoint[]{planetModel.SOUTH_POLE};
-
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    final double newTopLat = topLat + angle;
-    final double newBottomLat = -Math.PI * 0.5;
-    // Figuring out when we escalate to a special case requires some prefiguring
-    double currentLonSpan = rightLon - leftLon;
-    if (currentLonSpan < 0.0)
-      currentLonSpan += Math.PI * 2.0;
-    double newLeftLon = leftLon - angle;
-    double newRightLon = rightLon + angle;
-    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
-      newLeftLon = -Math.PI;
-      newRightLon = Math.PI;
-    }
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return topPlane.isWithin(x, y, z) &&
-        leftPlane.isWithin(x, y, z) &&
-        rightPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public double getRadius() {
-    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
-    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
-    // the distance to the right or left edge from the center.
-    final double centerAngle = (rightLon - (rightLon + leftLon) * 0.5) * cosMiddleLat;
-    final double topAngle = centerPoint.arcDistance(URHC);
-    return Math.max(centerAngle, topAngle);
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    return centerPoint;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    return p.intersects(planetModel, topPlane, notablePoints, topPlanePoints, bounds, leftPlane, rightPlane) ||
-        p.intersects(planetModel, leftPlane, notablePoints, leftPlanePoints, bounds, rightPlane, topPlane) ||
-        p.intersects(planetModel, rightPlane, notablePoints, rightPlanePoints, bounds, leftPlane, topPlane);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds
-      .addHorizontalPlane(planetModel, topLat, topPlane, leftPlane, rightPlane)
-      .addVerticalPlane(planetModel, leftLon, leftPlane, topPlane, rightPlane)
-      .addVerticalPlane(planetModel, rightLon, rightPlane, topPlane, leftPlane)
-      .addPoint(URHC).addPoint(ULHC).addPoint(planetModel.SOUTH_POLE);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    //System.err.println(this+" getrelationship with "+path);
-    final int insideRectangle = isShapeInsideBBox(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some inside");
-      return OVERLAPS;
-    }
-
-    final boolean insideShape = path.isWithin(planetModel.SOUTH_POLE);
-
-    if (insideRectangle == ALL_INSIDE && insideShape) {
-      //System.err.println(" inside of each other");
-      return OVERLAPS;
-    }
-
-    if (path.intersects(topPlane, topPlanePoints, leftPlane, rightPlane) ||
-        path.intersects(leftPlane, leftPlanePoints, topPlane, rightPlane) ||
-        path.intersects(rightPlane, rightPlanePoints, leftPlane, topPlane)) {
-      //System.err.println(" edges intersect");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      //System.err.println(" shape inside rectangle");
-      return WITHIN;
-    }
-
-    if (insideShape) {
-      //System.err.println(" shape contains rectangle");
-      return CONTAINS;
-    }
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    final double topDistance = distanceStyle.computeDistance(planetModel, topPlane, x,y,z, leftPlane, rightPlane);
-    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, rightPlane, topPlane);
-    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, leftPlane, topPlane);
-    
-    final double ULHCDistance = distanceStyle.computeDistance(ULHC, x,y,z);
-    final double URHCDistance = distanceStyle.computeDistance(URHC, x,y,z);
-    
-    return Math.min(
-      Math.min(
-        topDistance,
-        Math.min(leftDistance, rightDistance)),
-      Math.min(ULHCDistance, URHCDistance));
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoSouthRectangle))
-      return false;
-    GeoSouthRectangle other = (GeoSouthRectangle) o;
-    return super.equals(other) && other.ULHC.equals(ULHC) && other.URHC.equals(URHC);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + ULHC.hashCode();
-    result = 31 * result + URHC.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoSouthRectangle: {planetmodel="+planetModel+", toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
-  }
-}
-  
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoStandardCircle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoStandardCircle.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoStandardCircle.java
deleted file mode 100755
index 0304d53..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoStandardCircle.java
+++ /dev/null
@@ -1,168 +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.geo3d;
-
-/**
- * Circular area with a center and radius.
- *
- * @lucene.experimental
- */
-public class GeoStandardCircle extends GeoBaseCircle {
-  /** Center of circle */
-  protected final GeoPoint center;
-  /** Cutoff angle of circle (not quite the same thing as radius) */
-  protected final double cutoffAngle;
-  /** The plane describing the circle (really an ellipse on a non-spherical world) */
-  protected final SidedPlane circlePlane;
-  /** A point that is on the world and on the circle plane */
-  protected final GeoPoint[] edgePoints;
-  /** Notable points for a circle -- there aren't any */
-  protected static final GeoPoint[] circlePoints = new GeoPoint[0];
-
-  /** Constructor.
-   *@param planetModel is the planet model.
-   *@param lat is the center latitude.
-   *@param lon is the center longitude.
-   *@param cutoffAngle is the cutoff angle for the circle.
-   */
-  public GeoStandardCircle(final PlanetModel planetModel, final double lat, final double lon, final double cutoffAngle) {
-    super(planetModel);
-    if (lat < -Math.PI * 0.5 || lat > Math.PI * 0.5)
-      throw new IllegalArgumentException("Latitude out of bounds");
-    if (lon < -Math.PI || lon > Math.PI)
-      throw new IllegalArgumentException("Longitude out of bounds");
-    if (cutoffAngle < 0.0 || cutoffAngle > Math.PI)
-      throw new IllegalArgumentException("Cutoff angle out of bounds");
-    if (cutoffAngle < Vector.MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("Cutoff angle cannot be effectively zero");
-    this.center = new GeoPoint(planetModel, lat, lon);
-    // In an ellipsoidal world, cutoff distances make no sense, unfortunately.  Only membership
-    // can be used to make in/out determination.
-    this.cutoffAngle = cutoffAngle;
-    // Compute two points on the circle, with the right angle from the center.  We'll use these
-    // to obtain the perpendicular plane to the circle.
-    double upperLat = lat + cutoffAngle;
-    double upperLon = lon;
-    if (upperLat > Math.PI * 0.5) {
-      upperLon += Math.PI;
-      if (upperLon > Math.PI)
-        upperLon -= 2.0 * Math.PI;
-      upperLat = Math.PI - upperLat;
-    }
-    double lowerLat = lat - cutoffAngle;
-    double lowerLon = lon;
-    if (lowerLat < -Math.PI * 0.5) {
-      lowerLon += Math.PI;
-      if (lowerLon > Math.PI)
-        lowerLon -= 2.0 * Math.PI;
-      lowerLat = -Math.PI - lowerLat;
-    }
-    final GeoPoint upperPoint = new GeoPoint(planetModel, upperLat, upperLon);
-    final GeoPoint lowerPoint = new GeoPoint(planetModel, lowerLat, lowerLon);
-    if (Math.abs(cutoffAngle - Math.PI) < Vector.MINIMUM_RESOLUTION) {
-      // Circle is the whole world
-      this.circlePlane = null;
-      this.edgePoints = new GeoPoint[0];
-    } else {
-      // Construct normal plane
-      final Plane normalPlane = Plane.constructNormalizedZPlane(upperPoint, lowerPoint, center);
-      // Construct a sided plane that goes through the two points and whose normal is in the normalPlane.
-      this.circlePlane = SidedPlane.constructNormalizedPerpendicularSidedPlane(center, normalPlane, upperPoint, lowerPoint);
-      if (circlePlane == null)
-        throw new IllegalArgumentException("Couldn't construct circle plane, probably too small?  Cutoff angle = "+cutoffAngle+"; upperPoint = "+upperPoint+"; lowerPoint = "+lowerPoint);
-      final GeoPoint recomputedIntersectionPoint = circlePlane.getSampleIntersectionPoint(planetModel, normalPlane);
-      if (recomputedIntersectionPoint == null)
-        throw new IllegalArgumentException("Couldn't construct intersection point, probably circle too small?  Plane = "+circlePlane);
-      this.edgePoints = new GeoPoint[]{recomputedIntersectionPoint};
-    }
-  }
-
-  @Override
-  public double getRadius() {
-    return cutoffAngle;
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    return center;
-  }
-
-  @Override
-  protected double distance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    return distanceStyle.computeDistance(this.center, x, y, z);
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    return distanceStyle.computeDistance(planetModel, circlePlane, x, y, z);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    if (circlePlane == null) {
-      return true;
-    }
-    // Fastest way of determining membership
-    return circlePlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    if (circlePlane == null) {
-      return false;
-    }
-    return circlePlane.intersects(planetModel, p, notablePoints, circlePoints, bounds);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    if (circlePlane == null) {
-      // Entire world; should already be covered
-      return;
-    }
-    bounds.addPoint(center);
-    bounds.addPlane(planetModel, circlePlane);
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoStandardCircle))
-      return false;
-    GeoStandardCircle other = (GeoStandardCircle) o;
-    return super.equals(other) && other.center.equals(center) && other.cutoffAngle == cutoffAngle;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + center.hashCode();
-    long temp = Double.doubleToLongBits(cutoffAngle);
-    result = 31 * result + (int) (temp ^ (temp >>> 32));
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoStandardCircle: {planetmodel=" + planetModel+", center=" + center + ", radius=" + cutoffAngle + "(" + cutoffAngle * 180.0 / Math.PI + ")}";
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideDegenerateHorizontalLine.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideDegenerateHorizontalLine.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideDegenerateHorizontalLine.java
deleted file mode 100644
index a9af5b2..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideDegenerateHorizontalLine.java
+++ /dev/null
@@ -1,238 +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.geo3d;
-
-/**
- * Degenerate bounding box wider than PI and limited on two sides (left lon, right lon).
- *
- * @lucene.internal
- */
-public class GeoWideDegenerateHorizontalLine extends GeoBaseBBox {
-  /** The latitude of the line */
-  protected final double latitude;
-  /** The left longitude cutoff of the line */
-  protected final double leftLon;
-  /** The right longitude cutoff of the line */
-  protected final double rightLon;
-
-  /** The left end of the line */
-  protected final GeoPoint LHC;
-  /** The right end of the line */
-  protected final GeoPoint RHC;
-
-  /** The plane the line is in */
-  protected final Plane plane;
-  /** The left cutoff plane */
-  protected final SidedPlane leftPlane;
-  /** The right cutoff plane */
-  protected final SidedPlane rightPlane;
-
-  /** Notable points for the line */
-  protected final GeoPoint[] planePoints;
-
-  /** Center point for the line */
-  protected final GeoPoint centerPoint;
-
-  /** Left/right combination bound */
-  protected final EitherBound eitherBound;
-
-  /** A point on the line */
-  protected final GeoPoint[] edgePoints;
-
-  /**
-   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}.
-   * Horizontal angle must be greater than or equal to PI.
-   *@param planetModel is the planet model.
-   *@param latitude is the line latitude.
-   *@param leftLon is the left cutoff longitude.
-   *@param rightLon is the right cutoff longitude.
-   */
-  public GeoWideDegenerateHorizontalLine(final PlanetModel planetModel, final double latitude, final double leftLon, double rightLon) {
-    super(planetModel);
-    // Argument checking
-    if (latitude > Math.PI * 0.5 || latitude < -Math.PI * 0.5)
-      throw new IllegalArgumentException("Latitude out of range");
-    if (leftLon < -Math.PI || leftLon > Math.PI)
-      throw new IllegalArgumentException("Left longitude out of range");
-    if (rightLon < -Math.PI || rightLon > Math.PI)
-      throw new IllegalArgumentException("Right longitude out of range");
-    double extent = rightLon - leftLon;
-    if (extent < 0.0) {
-      extent += 2.0 * Math.PI;
-    }
-    if (extent < Math.PI)
-      throw new IllegalArgumentException("Width of rectangle too small");
-
-    this.latitude = latitude;
-    this.leftLon = leftLon;
-    this.rightLon = rightLon;
-
-    final double sinLatitude = Math.sin(latitude);
-    final double cosLatitude = Math.cos(latitude);
-    final double sinLeftLon = Math.sin(leftLon);
-    final double cosLeftLon = Math.cos(leftLon);
-    final double sinRightLon = Math.sin(rightLon);
-    final double cosRightLon = Math.cos(rightLon);
-
-    // Now build the two points
-    this.LHC = new GeoPoint(planetModel, sinLatitude, sinLeftLon, cosLatitude, cosLeftLon, latitude, leftLon);
-    this.RHC = new GeoPoint(planetModel, sinLatitude, sinRightLon, cosLatitude, cosRightLon, latitude, rightLon);
-
-    this.plane = new Plane(planetModel, sinLatitude);
-
-    // Normalize
-    while (leftLon > rightLon) {
-      rightLon += Math.PI * 2.0;
-    }
-    double middleLon = (leftLon + rightLon) * 0.5;
-    double sinMiddleLon = Math.sin(middleLon);
-    double cosMiddleLon = Math.cos(middleLon);
-
-    this.centerPoint = new GeoPoint(planetModel, sinLatitude, sinMiddleLon, cosLatitude, cosMiddleLon);
-
-    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
-    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
-
-    this.planePoints = new GeoPoint[]{LHC, RHC};
-
-    this.eitherBound = new EitherBound();
-
-    this.edgePoints = new GeoPoint[]{centerPoint};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    final double newTopLat = latitude + angle;
-    final double newBottomLat = latitude - angle;
-    // Figuring out when we escalate to a special case requires some prefiguring
-    double currentLonSpan = rightLon - leftLon;
-    if (currentLonSpan < 0.0)
-      currentLonSpan += Math.PI * 2.0;
-    double newLeftLon = leftLon - angle;
-    double newRightLon = rightLon + angle;
-    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
-      newLeftLon = -Math.PI;
-      newRightLon = Math.PI;
-    }
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return plane.evaluateIsZero(x, y, z) &&
-        (leftPlane.isWithin(x, y, z) ||
-            rightPlane.isWithin(x, y, z));
-  }
-
-  @Override
-  public double getRadius() {
-    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
-    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
-    // the distance to the right or left edge from the center.
-    final double topAngle = centerPoint.arcDistance(RHC);
-    final double bottomAngle = centerPoint.arcDistance(LHC);
-    return Math.max(topAngle, bottomAngle);
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    return centerPoint;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    // Right and left bounds are essentially independent hemispheres; crossing into the wrong part of one
-    // requires crossing into the right part of the other.  So intersection can ignore the left/right bounds.
-    return p.intersects(planetModel, plane, notablePoints, planePoints, bounds, eitherBound);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds.isWide()
-      .addHorizontalPlane(planetModel, latitude, plane, eitherBound)
-      .addPoint(LHC)
-      .addPoint(RHC);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    if (path.intersects(plane, planePoints, eitherBound)) {
-      return OVERLAPS;
-    }
-
-    if (path.isWithin(centerPoint)) {
-      return CONTAINS;
-    }
-
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    final double distance = distanceStyle.computeDistance(planetModel, plane, x,y,z, eitherBound);
-    
-    final double LHCDistance = distanceStyle.computeDistance(LHC, x,y,z);
-    final double RHCDistance = distanceStyle.computeDistance(RHC, x,y,z);
-    
-    return Math.min(
-      distance,
-      Math.min(LHCDistance, RHCDistance));
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoWideDegenerateHorizontalLine))
-      return false;
-    GeoWideDegenerateHorizontalLine other = (GeoWideDegenerateHorizontalLine) o;
-    return super.equals(other) && other.LHC.equals(LHC) && other.RHC.equals(RHC);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + LHC.hashCode();
-    result = 31 * result + RHC.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoWideDegenerateHorizontalLine: {planetmodel="+planetModel+", latitude=" + latitude + "(" + latitude * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightLon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
-  }
-
-  /** Membership implementation representing a wide cutoff (more than 180 degrees).
-   */
-  protected class EitherBound implements Membership {
-    /** Constructor.
-     */
-    public EitherBound() {
-    }
-
-    @Override
-    public boolean isWithin(final double x, final double y, final double z) {
-      return leftPlane.isWithin(x, y, z) || rightPlane.isWithin(x, y, z);
-    }
-  }
-}
-  
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideLongitudeSlice.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideLongitudeSlice.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideLongitudeSlice.java
deleted file mode 100755
index 64e4fa8..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideLongitudeSlice.java
+++ /dev/null
@@ -1,208 +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.geo3d;
-
-/**
- * Bounding box wider than PI but limited on left and right sides (
- * left lon, right lon).
- *
- * @lucene.internal
- */
-public class GeoWideLongitudeSlice extends GeoBaseBBox {
-  /** The left longitude */
-  protected final double leftLon;
-  /** The right longitude */
-  protected final double rightLon;
-
-  /** The left plane */
-  protected final SidedPlane leftPlane;
-  /** The right plane */
-  protected final SidedPlane rightPlane;
-
-  /** Notable points for the shape */
-  protected final GeoPoint[] planePoints;
-
-  /** Center point for the shape */
-  protected final GeoPoint centerPoint;
-
-  /** A point on the edge of the shape */
-  protected final GeoPoint[] edgePoints; 
-
-  /**
-   * Accepts only values in the following ranges: lon: {@code -PI -> PI}.
-   * Horizantal angle must be greater than or equal to PI.
-   *@param planetModel is the planet model.
-   *@param leftLon is the left longitude.
-   *@param rightLon is the right longitude.
-   */
-  public GeoWideLongitudeSlice(final PlanetModel planetModel, final double leftLon, double rightLon) {
-    super(planetModel);
-    // Argument checking
-    if (leftLon < -Math.PI || leftLon > Math.PI)
-      throw new IllegalArgumentException("Left longitude out of range");
-    if (rightLon < -Math.PI || rightLon > Math.PI)
-      throw new IllegalArgumentException("Right longitude out of range");
-    double extent = rightLon - leftLon;
-    if (extent < 0.0) {
-      extent += 2.0 * Math.PI;
-    }
-    if (extent < Math.PI)
-      throw new IllegalArgumentException("Width of rectangle too small");
-
-    this.leftLon = leftLon;
-    this.rightLon = rightLon;
-
-    final double sinLeftLon = Math.sin(leftLon);
-    final double cosLeftLon = Math.cos(leftLon);
-    final double sinRightLon = Math.sin(rightLon);
-    final double cosRightLon = Math.cos(rightLon);
-
-    // Normalize
-    while (leftLon > rightLon) {
-      rightLon += Math.PI * 2.0;
-    }
-    final double middleLon = (leftLon + rightLon) * 0.5;
-    this.centerPoint = new GeoPoint(planetModel, 0.0, middleLon);
-
-    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
-    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
-    
-    this.planePoints = new GeoPoint[]{planetModel.NORTH_POLE, planetModel.SOUTH_POLE};
-    this.edgePoints = new GeoPoint[]{planetModel.NORTH_POLE};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    // Figuring out when we escalate to a special case requires some prefiguring
-    double currentLonSpan = rightLon - leftLon;
-    if (currentLonSpan < 0.0)
-      currentLonSpan += Math.PI * 2.0;
-    double newLeftLon = leftLon - angle;
-    double newRightLon = rightLon + angle;
-    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
-      newLeftLon = -Math.PI;
-      newRightLon = Math.PI;
-    }
-    return GeoBBoxFactory.makeGeoBBox(planetModel, Math.PI * 0.5, -Math.PI * 0.5, newLeftLon, newRightLon);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return leftPlane.isWithin(x, y, z) ||
-        rightPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public double getRadius() {
-    // Compute the extent and divide by two
-    double extent = rightLon - leftLon;
-    if (extent < 0.0)
-      extent += Math.PI * 2.0;
-    return Math.max(Math.PI * 0.5, extent * 0.5);
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    return centerPoint;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    // Right and left bounds are essentially independent hemispheres; crossing into the wrong part of one
-    // requires crossing into the right part of the other.  So intersection can ignore the left/right bounds.
-    return p.intersects(planetModel, leftPlane, notablePoints, planePoints, bounds) ||
-        p.intersects(planetModel, rightPlane, notablePoints, planePoints, bounds);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds.isWide()
-      .addVerticalPlane(planetModel, leftLon, leftPlane)
-      .addVerticalPlane(planetModel, rightLon, rightPlane)
-      .addPoint(planetModel.NORTH_POLE)
-      .addPoint(planetModel.SOUTH_POLE);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    final int insideRectangle = isShapeInsideBBox(path);
-    if (insideRectangle == SOME_INSIDE)
-      return OVERLAPS;
-
-    final boolean insideShape = path.isWithin(planetModel.NORTH_POLE);
-
-    if (insideRectangle == ALL_INSIDE && insideShape)
-      return OVERLAPS;
-
-    if (path.intersects(leftPlane, planePoints) ||
-        path.intersects(rightPlane, planePoints))
-      return OVERLAPS;
-
-    if (insideRectangle == ALL_INSIDE)
-      return WITHIN;
-
-    if (insideShape)
-      return CONTAINS;
-
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    // Because the rectangle exceeds 180 degrees, it is safe to compute the horizontally 
-    // unbounded distance to both the left and the right and only take the minimum of the two.
-    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z);
-    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z);
-    
-    final double northDistance = distanceStyle.computeDistance(planetModel.NORTH_POLE, x,y,z);
-    final double southDistance = distanceStyle.computeDistance(planetModel.SOUTH_POLE, x,y,z);
-    
-    return Math.min(
-      Math.min(leftDistance, rightDistance),
-      Math.min(northDistance, southDistance));
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoWideLongitudeSlice))
-      return false;
-    GeoWideLongitudeSlice other = (GeoWideLongitudeSlice) o;
-    return super.equals(other) && other.leftLon == leftLon && other.rightLon == rightLon;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    long temp = Double.doubleToLongBits(leftLon);
-    result = 31 * result + (int) (temp ^ (temp >>> 32));
-    temp = Double.doubleToLongBits(rightLon);
-    result = 31 * result + (int) (temp ^ (temp >>> 32));
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoWideLongitudeSlice: {planetmodel="+planetModel+", leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
-  }
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideNorthRectangle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideNorthRectangle.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideNorthRectangle.java
deleted file mode 100644
index 86de584..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideNorthRectangle.java
+++ /dev/null
@@ -1,286 +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.geo3d;
-
-/**
- * Bounding box wider than PI but limited on three sides (
- * bottom lat, left lon, right lon).
- *
- * @lucene.internal
- */
-public class GeoWideNorthRectangle extends GeoBaseBBox {
-  /** Bottom latitude */
-  protected final double bottomLat;
-  /** Left longitude */
-  protected final double leftLon;
-  /** Right longitude */
-  protected final double rightLon;
-
-  /** The cosine of the middle latitude */
-  protected final double cosMiddleLat;
-
-  /** The lower right hand corner point */
-  protected final GeoPoint LRHC;
-  /** The lower left hand corner point */
-  protected final GeoPoint LLHC;
-
-  /** The bottom plane */
-  protected final SidedPlane bottomPlane;
-  /** The left plane */
-  protected final SidedPlane leftPlane;
-  /** The right plane */
-  protected final SidedPlane rightPlane;
-
-  /** Notable points for the bottom plane */
-  protected final GeoPoint[] bottomPlanePoints;
-  /** Notable points for the left plane */
-  protected final GeoPoint[] leftPlanePoints;
-  /** Notable points for the right plane */
-  protected final GeoPoint[] rightPlanePoints;
-
-  /** Center point */
-  protected final GeoPoint centerPoint;
-
-  /** Composite left/right bounds */
-  protected final EitherBound eitherBound;
-
-  /** A point on the edge */
-  protected final GeoPoint[] edgePoints;
-
-  /**
-   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}.
-   * Horizontal angle must be greater than or equal to PI.
-   */
-  public GeoWideNorthRectangle(final PlanetModel planetModel, final double bottomLat, final double leftLon, double rightLon) {
-    super(planetModel);
-    // Argument checking
-    if (bottomLat > Math.PI * 0.5 || bottomLat < -Math.PI * 0.5)
-      throw new IllegalArgumentException("Bottom latitude out of range");
-    if (leftLon < -Math.PI || leftLon > Math.PI)
-      throw new IllegalArgumentException("Left longitude out of range");
-    if (rightLon < -Math.PI || rightLon > Math.PI)
-      throw new IllegalArgumentException("Right longitude out of range");
-    double extent = rightLon - leftLon;
-    if (extent < 0.0) {
-      extent += 2.0 * Math.PI;
-    }
-    if (extent < Math.PI)
-      throw new IllegalArgumentException("Width of rectangle too small");
-
-    this.bottomLat = bottomLat;
-    this.leftLon = leftLon;
-    this.rightLon = rightLon;
-
-    final double sinBottomLat = Math.sin(bottomLat);
-    final double cosBottomLat = Math.cos(bottomLat);
-    final double sinLeftLon = Math.sin(leftLon);
-    final double cosLeftLon = Math.cos(leftLon);
-    final double sinRightLon = Math.sin(rightLon);
-    final double cosRightLon = Math.cos(rightLon);
-
-    // Now build the four points
-    this.LRHC = new GeoPoint(planetModel, sinBottomLat, sinRightLon, cosBottomLat, cosRightLon, bottomLat, rightLon);
-    this.LLHC = new GeoPoint(planetModel, sinBottomLat, sinLeftLon, cosBottomLat, cosLeftLon, bottomLat, leftLon);
-
-    final double middleLat = (Math.PI * 0.5 + bottomLat) * 0.5;
-    final double sinMiddleLat = Math.sin(middleLat);
-    this.cosMiddleLat = Math.cos(middleLat);
-    // Normalize
-    while (leftLon > rightLon) {
-      rightLon += Math.PI * 2.0;
-    }
-    final double middleLon = (leftLon + rightLon) * 0.5;
-    final double sinMiddleLon = Math.sin(middleLon);
-    final double cosMiddleLon = Math.cos(middleLon);
-
-    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinMiddleLon, cosMiddleLat, cosMiddleLon);
-
-    this.bottomPlane = new SidedPlane(centerPoint, planetModel, sinBottomLat);
-    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
-    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
-
-    this.bottomPlanePoints = new GeoPoint[]{LLHC, LRHC};
-    this.leftPlanePoints = new GeoPoint[]{planetModel.NORTH_POLE, LLHC};
-    this.rightPlanePoints = new GeoPoint[]{planetModel.NORTH_POLE, LRHC};
-
-    this.eitherBound = new EitherBound();
-    this.edgePoints = new GeoPoint[]{planetModel.NORTH_POLE};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    final double newTopLat = Math.PI * 0.5;
-    final double newBottomLat = bottomLat - angle;
-    // Figuring out when we escalate to a special case requires some prefiguring
-    double currentLonSpan = rightLon - leftLon;
-    if (currentLonSpan < 0.0)
-      currentLonSpan += Math.PI * 2.0;
-    double newLeftLon = leftLon - angle;
-    double newRightLon = rightLon + angle;
-    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
-      newLeftLon = -Math.PI;
-      newRightLon = Math.PI;
-    }
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return
-        bottomPlane.isWithin(x, y, z) &&
-            (leftPlane.isWithin(x, y, z) ||
-                rightPlane.isWithin(x, y, z));
-  }
-
-  @Override
-  public double getRadius() {
-    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
-    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
-    // the distance to the right or left edge from the center.
-    final double centerAngle = (rightLon - (rightLon + leftLon) * 0.5) * cosMiddleLat;
-    final double bottomAngle = centerPoint.arcDistance(LLHC);
-    return Math.max(centerAngle, bottomAngle);
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    return centerPoint;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    // Right and left bounds are essentially independent hemispheres; crossing into the wrong part of one
-    // requires crossing into the right part of the other.  So intersection can ignore the left/right bounds.
-    return
-        p.intersects(planetModel, bottomPlane, notablePoints, bottomPlanePoints, bounds, eitherBound) ||
-            p.intersects(planetModel, leftPlane, notablePoints, leftPlanePoints, bounds, bottomPlane) ||
-            p.intersects(planetModel, rightPlane, notablePoints, rightPlanePoints, bounds, bottomPlane);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds.isWide()
-      .addHorizontalPlane(planetModel, bottomLat, bottomPlane, eitherBound)
-      .addVerticalPlane(planetModel, leftLon, leftPlane, bottomPlane)
-      .addVerticalPlane(planetModel, rightLon, rightPlane, bottomPlane)
-      .addPoint(LLHC).addPoint(LRHC).addPoint(planetModel.NORTH_POLE);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    //System.err.println(this+" comparing to "+path);
-    final int insideRectangle = isShapeInsideBBox(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some inside");
-      return OVERLAPS;
-    }
-
-    final boolean insideShape = path.isWithin(planetModel.NORTH_POLE);
-
-    if (insideRectangle == ALL_INSIDE && insideShape) {
-      //System.err.println(" both inside each other");
-      return OVERLAPS;
-    }
-
-    if (
-        path.intersects(bottomPlane, bottomPlanePoints, eitherBound) ||
-            path.intersects(leftPlane, leftPlanePoints, bottomPlane) ||
-            path.intersects(rightPlane, rightPlanePoints, bottomPlane)) {
-      //System.err.println(" edges intersect");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      //System.err.println(" shape inside rectangle");
-      return WITHIN;
-    }
-
-    if (insideShape) {
-      //System.err.println(" rectangle inside shape");
-      return CONTAINS;
-    }
-
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    final double bottomDistance = distanceStyle.computeDistance(planetModel, bottomPlane, x,y,z, eitherBound);
-    // Because the rectangle exceeds 180 degrees, it is safe to compute the horizontally 
-    // unbounded distance to both the left and the right and only take the minimum of the two.
-    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, bottomPlane);
-    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, bottomPlane);
-    
-    final double LRHCDistance = distanceStyle.computeDistance(LRHC, x,y,z);
-    final double LLHCDistance = distanceStyle.computeDistance(LLHC, x,y,z);
-    
-    return Math.min(
-      Math.min(
-        bottomDistance,
-        Math.min(leftDistance, rightDistance)),
-      Math.min(LRHCDistance, LLHCDistance));
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoWideNorthRectangle))
-      return false;
-    GeoWideNorthRectangle other = (GeoWideNorthRectangle) o;
-    return super.equals(other) && other.LLHC.equals(LLHC) && other.LRHC.equals(LRHC);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + LLHC.hashCode();
-    result = 31 * result + LRHC.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoWideNorthRectangle: {planetmodel="+planetModel+", bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
-  }
-
-  /** Membership implementation representing a wide (more than 180 degree) bound.
-   */
-  protected class EitherBound implements Membership {
-    /** Constructor.
-     */
-    public EitherBound() {
-    }
-
-    @Override
-    public boolean isWithin(final Vector v) {
-      return leftPlane.isWithin(v) || rightPlane.isWithin(v);
-    }
-
-    @Override
-    public boolean isWithin(final double x, final double y, final double z) {
-      return leftPlane.isWithin(x, y, z) || rightPlane.isWithin(x, y, z);
-    }
-  }
-}
-  
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideRectangle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideRectangle.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideRectangle.java
deleted file mode 100755
index 68397bb..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideRectangle.java
+++ /dev/null
@@ -1,319 +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.geo3d;
-
-/**
- * Bounding box wider than PI but limited on four sides (top lat,
- * bottom lat, left lon, right lon).
- *
- * @lucene.internal
- */
-public class GeoWideRectangle extends GeoBaseBBox {
-  /** The top latitude */
-  protected final double topLat;
-  /** The bottom latitude */
-  protected final double bottomLat;
-  /** The left longitude */
-  protected final double leftLon;
-  /** The right longitude */
-  protected final double rightLon;
-
-  /** Cosine of the middle latitude */
-  protected final double cosMiddleLat;
-
-  /** Upper left hand corner point */
-  protected final GeoPoint ULHC;
-  /** Lower right hand corner point */
-  protected final GeoPoint URHC;
-  /** Lower right hand corner point */
-  protected final GeoPoint LRHC;
-  /** Lower left hand corner point */
-  protected final GeoPoint LLHC;
-
-  /** Top plane */
-  protected final SidedPlane topPlane;
-  /** Bottom plane */
-  protected final SidedPlane bottomPlane;
-  /** Left plane */
-  protected final SidedPlane leftPlane;
-  /** Right plane */
-  protected final SidedPlane rightPlane;
-
-  /** Top plane's notable points */
-  protected final GeoPoint[] topPlanePoints;
-  /** Bottom plane's notable points */
-  protected final GeoPoint[] bottomPlanePoints;
-  /** Left plane's notable points */
-  protected final GeoPoint[] leftPlanePoints;
-  /** Right plane's notable points */
-  protected final GeoPoint[] rightPlanePoints;
-
-  /** Center point */
-  protected final GeoPoint centerPoint;
-
-  /** Combined left/right bounds */
-  protected final EitherBound eitherBound;
-
-  /** A point on the edge */
-  protected final GeoPoint[] edgePoints;
-
-  /**
-   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}.
-   * Horizontal angle must be greater than or equal to PI.
-   */
-  public GeoWideRectangle(final PlanetModel planetModel, final double topLat, final double bottomLat, final double leftLon, double rightLon) {
-    super(planetModel);
-    // Argument checking
-    if (topLat > Math.PI * 0.5 || topLat < -Math.PI * 0.5)
-      throw new IllegalArgumentException("Top latitude out of range");
-    if (bottomLat > Math.PI * 0.5 || bottomLat < -Math.PI * 0.5)
-      throw new IllegalArgumentException("Bottom latitude out of range");
-    if (topLat < bottomLat)
-      throw new IllegalArgumentException("Top latitude less than bottom latitude");
-    if (leftLon < -Math.PI || leftLon > Math.PI)
-      throw new IllegalArgumentException("Left longitude out of range");
-    if (rightLon < -Math.PI || rightLon > Math.PI)
-      throw new IllegalArgumentException("Right longitude out of range");
-    double extent = rightLon - leftLon;
-    if (extent < 0.0) {
-      extent += 2.0 * Math.PI;
-    }
-    if (extent < Math.PI)
-      throw new IllegalArgumentException("Width of rectangle too small");
-
-    this.topLat = topLat;
-    this.bottomLat = bottomLat;
-    this.leftLon = leftLon;
-    this.rightLon = rightLon;
-
-    final double sinTopLat = Math.sin(topLat);
-    final double cosTopLat = Math.cos(topLat);
-    final double sinBottomLat = Math.sin(bottomLat);
-    final double cosBottomLat = Math.cos(bottomLat);
-    final double sinLeftLon = Math.sin(leftLon);
-    final double cosLeftLon = Math.cos(leftLon);
-    final double sinRightLon = Math.sin(rightLon);
-    final double cosRightLon = Math.cos(rightLon);
-
-    // Now build the four points
-    this.ULHC = new GeoPoint(planetModel, sinTopLat, sinLeftLon, cosTopLat, cosLeftLon, topLat, leftLon);
-    this.URHC = new GeoPoint(planetModel, sinTopLat, sinRightLon, cosTopLat, cosRightLon, topLat, rightLon);
-    this.LRHC = new GeoPoint(planetModel, sinBottomLat, sinRightLon, cosBottomLat, cosRightLon, bottomLat, rightLon);
-    this.LLHC = new GeoPoint(planetModel, sinBottomLat, sinLeftLon, cosBottomLat, cosLeftLon, bottomLat, leftLon);
-
-    final double middleLat = (topLat + bottomLat) * 0.5;
-    final double sinMiddleLat = Math.sin(middleLat);
-    this.cosMiddleLat = Math.cos(middleLat);
-    // Normalize
-    while (leftLon > rightLon) {
-      rightLon += Math.PI * 2.0;
-    }
-    final double middleLon = (leftLon + rightLon) * 0.5;
-    final double sinMiddleLon = Math.sin(middleLon);
-    final double cosMiddleLon = Math.cos(middleLon);
-
-    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinMiddleLon, cosMiddleLat, cosMiddleLon);
-
-    this.topPlane = new SidedPlane(centerPoint, planetModel, sinTopLat);
-    this.bottomPlane = new SidedPlane(centerPoint, planetModel, sinBottomLat);
-    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
-    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
-
-    this.topPlanePoints = new GeoPoint[]{ULHC, URHC};
-    this.bottomPlanePoints = new GeoPoint[]{LLHC, LRHC};
-    this.leftPlanePoints = new GeoPoint[]{ULHC, LLHC};
-    this.rightPlanePoints = new GeoPoint[]{URHC, LRHC};
-
-    this.eitherBound = new EitherBound();
-
-    this.edgePoints = new GeoPoint[]{ULHC};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    final double newTopLat = topLat + angle;
-    final double newBottomLat = bottomLat - angle;
-    // Figuring out when we escalate to a special case requires some prefiguring
-    double currentLonSpan = rightLon - leftLon;
-    if (currentLonSpan < 0.0)
-      currentLonSpan += Math.PI * 2.0;
-    double newLeftLon = leftLon - angle;
-    double newRightLon = rightLon + angle;
-    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
-      newLeftLon = -Math.PI;
-      newRightLon = Math.PI;
-    }
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return topPlane.isWithin(x, y, z) &&
-        bottomPlane.isWithin(x, y, z) &&
-        (leftPlane.isWithin(x, y, z) ||
-            rightPlane.isWithin(x, y, z));
-  }
-
-  @Override
-  public double getRadius() {
-    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
-    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
-    // the distance to the right or left edge from the center.
-    final double centerAngle = (rightLon - (rightLon + leftLon) * 0.5) * cosMiddleLat;
-    final double topAngle = centerPoint.arcDistance(URHC);
-    final double bottomAngle = centerPoint.arcDistance(LLHC);
-    return Math.max(centerAngle, Math.max(topAngle, bottomAngle));
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  /**
-   * Returns the center of a circle into which the area will be inscribed.
-   *
-   * @return the center.
-   */
-  @Override
-  public GeoPoint getCenter() {
-    return centerPoint;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    // Right and left bounds are essentially independent hemispheres; crossing into the wrong part of one
-    // requires crossing into the right part of the other.  So intersection can ignore the left/right bounds.
-    return p.intersects(planetModel, topPlane, notablePoints, topPlanePoints, bounds, bottomPlane, eitherBound) ||
-        p.intersects(planetModel, bottomPlane, notablePoints, bottomPlanePoints, bounds, topPlane, eitherBound) ||
-        p.intersects(planetModel, leftPlane, notablePoints, leftPlanePoints, bounds, topPlane, bottomPlane) ||
-        p.intersects(planetModel, rightPlane, notablePoints, rightPlanePoints, bounds, topPlane, bottomPlane);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds.isWide()
-      .addHorizontalPlane(planetModel, topLat, topPlane, bottomPlane, eitherBound)
-      .addVerticalPlane(planetModel, rightLon, rightPlane, topPlane, bottomPlane)
-      .addHorizontalPlane(planetModel, bottomLat, bottomPlane, topPlane, eitherBound)
-      .addVerticalPlane(planetModel, leftLon, leftPlane, topPlane, bottomPlane)
-      .addPoint(ULHC).addPoint(URHC).addPoint(LRHC).addPoint(LLHC);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    //System.err.println(this+" comparing to "+path);
-    final int insideRectangle = isShapeInsideBBox(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some inside");
-      return OVERLAPS;
-    }
-
-    final boolean insideShape = path.isWithin(ULHC);
-
-    if (insideRectangle == ALL_INSIDE && insideShape) {
-      //System.err.println(" both inside each other");
-      return OVERLAPS;
-    }
-
-    if (path.intersects(topPlane, topPlanePoints, bottomPlane, eitherBound) ||
-        path.intersects(bottomPlane, bottomPlanePoints, topPlane, eitherBound) ||
-        path.intersects(leftPlane, leftPlanePoints, topPlane, bottomPlane) ||
-        path.intersects(rightPlane, rightPlanePoints, topPlane, bottomPlane)) {
-      //System.err.println(" edges intersect");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      //System.err.println(" shape inside rectangle");
-      return WITHIN;
-    }
-
-    if (insideShape) {
-      //System.err.println(" rectangle inside shape");
-      return CONTAINS;
-    }
-
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    final double topDistance = distanceStyle.computeDistance(planetModel, topPlane, x,y,z, bottomPlane, eitherBound);
-    final double bottomDistance = distanceStyle.computeDistance(planetModel, bottomPlane, x,y,z, topPlane, eitherBound);
-    // Because the rectangle exceeds 180 degrees, it is safe to compute the horizontally 
-    // unbounded distance to both the left and the right and only take the minimum of the two.
-    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, topPlane, bottomPlane);
-    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, topPlane, bottomPlane);
-    
-    final double ULHCDistance = distanceStyle.computeDistance(ULHC, x,y,z);
-    final double URHCDistance = distanceStyle.computeDistance(URHC, x,y,z);
-    final double LRHCDistance = distanceStyle.computeDistance(LRHC, x,y,z);
-    final double LLHCDistance = distanceStyle.computeDistance(LLHC, x,y,z);
-    
-    return Math.min(
-      Math.min(
-        Math.min(topDistance, bottomDistance),
-        Math.min(leftDistance, rightDistance)),
-      Math.min(
-        Math.min(ULHCDistance, URHCDistance),
-        Math.min(LRHCDistance, LLHCDistance)));
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoWideRectangle))
-      return false;
-    GeoWideRectangle other = (GeoWideRectangle) o;
-    return super.equals(other) && other.ULHC.equals(ULHC) && other.LRHC.equals(LRHC);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + ULHC.hashCode();
-    result = 31 * result + LRHC.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoWideRectangle: {planetmodel=" + planetModel + ", toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + "), bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
-  }
-
-  /** A membership implementation representing a wide (more than 180) left/right bound.
-   */
-  protected class EitherBound implements Membership {
-    /** Constructor.
-      */
-    public EitherBound() {
-    }
-
-    @Override
-    public boolean isWithin(final Vector v) {
-      return leftPlane.isWithin(v) || rightPlane.isWithin(v);
-    }
-
-    @Override
-    public boolean isWithin(final double x, final double y, final double z) {
-      return leftPlane.isWithin(x, y, z) || rightPlane.isWithin(x, y, z);
-    }
-  }
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideSouthRectangle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideSouthRectangle.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideSouthRectangle.java
deleted file mode 100644
index 8bd7220..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideSouthRectangle.java
+++ /dev/null
@@ -1,284 +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.geo3d;
-
-/**
- * Bounding box wider than PI but limited on three sides (top lat,
- * left lon, right lon).
- *
- * @lucene.internal
- */
-public class GeoWideSouthRectangle extends GeoBaseBBox {
-  /** Top latitude of rect */
-  protected final double topLat;
-  /** Left longitude of rect */
-  protected final double leftLon;
-  /** Right longitude of rect */
-  protected final double rightLon;
-
-  /** Cosine of middle latitude */
-  protected final double cosMiddleLat;
-
-  /** Upper left hand corner */
-  protected final GeoPoint ULHC;
-  /** Upper right hand corner */
-  protected final GeoPoint URHC;
-
-  /** The top plane */
-  protected final SidedPlane topPlane;
-  /** The left plane */
-  protected final SidedPlane leftPlane;
-  /** The right plane */
-  protected final SidedPlane rightPlane;
-
-  /** Notable points for top plane */
-  protected final GeoPoint[] topPlanePoints;
-  /** Notable points for left plane */
-  protected final GeoPoint[] leftPlanePoints;
-  /** Notable points for right plane */
-  protected final GeoPoint[] rightPlanePoints;
-
-  /** Center point */
-  protected final GeoPoint centerPoint;
-
-  /** Left/right bounds */
-  protected final EitherBound eitherBound;
-
-  /** A point on the edge */
-  protected final GeoPoint[] edgePoints;
-
-  /**
-   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}.
-   * Horizontal angle must be greater than or equal to PI.
-   */
-  public GeoWideSouthRectangle(final PlanetModel planetModel, final double topLat, final double leftLon, double rightLon) {
-    super(planetModel);
-    // Argument checking
-    if (topLat > Math.PI * 0.5 || topLat < -Math.PI * 0.5)
-      throw new IllegalArgumentException("Top latitude out of range");
-    if (leftLon < -Math.PI || leftLon > Math.PI)
-      throw new IllegalArgumentException("Left longitude out of range");
-    if (rightLon < -Math.PI || rightLon > Math.PI)
-      throw new IllegalArgumentException("Right longitude out of range");
-    double extent = rightLon - leftLon;
-    if (extent < 0.0) {
-      extent += 2.0 * Math.PI;
-    }
-    if (extent < Math.PI)
-      throw new IllegalArgumentException("Width of rectangle too small");
-
-    this.topLat = topLat;
-    this.leftLon = leftLon;
-    this.rightLon = rightLon;
-
-    final double sinTopLat = Math.sin(topLat);
-    final double cosTopLat = Math.cos(topLat);
-    final double sinLeftLon = Math.sin(leftLon);
-    final double cosLeftLon = Math.cos(leftLon);
-    final double sinRightLon = Math.sin(rightLon);
-    final double cosRightLon = Math.cos(rightLon);
-
-    // Now build the four points
-    this.ULHC = new GeoPoint(planetModel, sinTopLat, sinLeftLon, cosTopLat, cosLeftLon, topLat, leftLon);
-    this.URHC = new GeoPoint(planetModel, sinTopLat, sinRightLon, cosTopLat, cosRightLon, topLat, rightLon);
-
-    final double middleLat = (topLat - Math.PI * 0.5) * 0.5;
-    final double sinMiddleLat = Math.sin(middleLat);
-    this.cosMiddleLat = Math.cos(middleLat);
-    // Normalize
-    while (leftLon > rightLon) {
-      rightLon += Math.PI * 2.0;
-    }
-    final double middleLon = (leftLon + rightLon) * 0.5;
-    final double sinMiddleLon = Math.sin(middleLon);
-    final double cosMiddleLon = Math.cos(middleLon);
-
-    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinMiddleLon, cosMiddleLat, cosMiddleLon);
-
-    this.topPlane = new SidedPlane(centerPoint, planetModel, sinTopLat);
-    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
-    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
-
-    this.topPlanePoints = new GeoPoint[]{ULHC, URHC};
-    this.leftPlanePoints = new GeoPoint[]{ULHC, planetModel.SOUTH_POLE};
-    this.rightPlanePoints = new GeoPoint[]{URHC, planetModel.SOUTH_POLE};
-
-    this.eitherBound = new EitherBound();
-    
-    this.edgePoints = new GeoPoint[]{planetModel.SOUTH_POLE};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    final double newTopLat = topLat + angle;
-    final double newBottomLat = -Math.PI * 0.5;
-    // Figuring out when we escalate to a special case requires some prefiguring
-    double currentLonSpan = rightLon - leftLon;
-    if (currentLonSpan < 0.0)
-      currentLonSpan += Math.PI * 2.0;
-    double newLeftLon = leftLon - angle;
-    double newRightLon = rightLon + angle;
-    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
-      newLeftLon = -Math.PI;
-      newRightLon = Math.PI;
-    }
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return topPlane.isWithin(x, y, z) &&
-        (leftPlane.isWithin(x, y, z) ||
-            rightPlane.isWithin(x, y, z));
-  }
-
-  @Override
-  public double getRadius() {
-    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
-    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
-    // the distance to the right or left edge from the center.
-    final double centerAngle = (rightLon - (rightLon + leftLon) * 0.5) * cosMiddleLat;
-    final double topAngle = centerPoint.arcDistance(URHC);
-    return Math.max(centerAngle, topAngle);
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    return centerPoint;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    // Right and left bounds are essentially independent hemispheres; crossing into the wrong part of one
-    // requires crossing into the right part of the other.  So intersection can ignore the left/right bounds.
-    return p.intersects(planetModel, topPlane, notablePoints, topPlanePoints, bounds, eitherBound) ||
-        p.intersects(planetModel, leftPlane, notablePoints, leftPlanePoints, bounds, topPlane) ||
-        p.intersects(planetModel, rightPlane, notablePoints, rightPlanePoints, bounds, topPlane);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds.isWide()
-      .addHorizontalPlane(planetModel, topLat, topPlane, eitherBound)
-      .addVerticalPlane(planetModel, rightLon, rightPlane, topPlane)
-      .addVerticalPlane(planetModel, leftLon, leftPlane, topPlane)
-      .addPoint(ULHC).addPoint(URHC).addPoint(planetModel.SOUTH_POLE);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    //System.err.println(this+" comparing to "+path);
-    final int insideRectangle = isShapeInsideBBox(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some inside");
-      return OVERLAPS;
-    }
-
-    final boolean insideShape = path.isWithin(planetModel.SOUTH_POLE);
-
-    if (insideRectangle == ALL_INSIDE && insideShape) {
-      //System.err.println(" both inside each other");
-      return OVERLAPS;
-    }
-
-    if (path.intersects(topPlane, topPlanePoints, eitherBound) ||
-        path.intersects(leftPlane, leftPlanePoints, topPlane) ||
-        path.intersects(rightPlane, rightPlanePoints, topPlane)) {
-      //System.err.println(" edges intersect");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      //System.err.println(" shape inside rectangle");
-      return WITHIN;
-    }
-
-    if (insideShape) {
-      //System.err.println(" rectangle inside shape");
-      return CONTAINS;
-    }
-
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    final double topDistance = distanceStyle.computeDistance(planetModel, topPlane, x,y,z, eitherBound);
-    // Because the rectangle exceeds 180 degrees, it is safe to compute the horizontally 
-    // unbounded distance to both the left and the right and only take the minimum of the two.
-    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, topPlane);
-    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, topPlane);
-    
-    final double ULHCDistance = distanceStyle.computeDistance(ULHC, x,y,z);
-    final double URHCDistance = distanceStyle.computeDistance(URHC, x,y,z);
-    
-    return Math.min(
-      Math.min(
-        topDistance,
-        Math.min(leftDistance, rightDistance)),
-      Math.min(ULHCDistance, URHCDistance));
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoWideSouthRectangle))
-      return false;
-    GeoWideSouthRectangle other = (GeoWideSouthRectangle) o;
-    return super.equals(o) && other.ULHC.equals(ULHC) && other.URHC.equals(URHC);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + ULHC.hashCode();
-    result = 31 * result + URHC.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoWideSouthRectangle: {planetmodel="+planetModel+", toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
-  }
-
-  /** Membership implementation representing width more than 180.
-   */
-  protected class EitherBound implements Membership {
-    /** Constructor.
-     */
-    public EitherBound() {
-    }
-
-    @Override
-    public boolean isWithin(final Vector v) {
-      return leftPlane.isWithin(v) || rightPlane.isWithin(v);
-    }
-
-    @Override
-    public boolean isWithin(final double x, final double y, final double z) {
-      return leftPlane.isWithin(x, y, z) || rightPlane.isWithin(x, y, z);
-    }
-  }
-}
-  
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWorld.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWorld.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWorld.java
deleted file mode 100755
index 35ec4ae..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWorld.java
+++ /dev/null
@@ -1,106 +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.geo3d;
-
-/**
- * Bounding box including the entire world.
- *
- * @lucene.internal
- */
-public class GeoWorld extends GeoBaseBBox {
-  /** No points on the edge of the shape */
-  protected final static GeoPoint[] edgePoints = new GeoPoint[0];
-  /** Point in the middle of the world */
-  protected final GeoPoint originPoint;
-  
-  /** Constructor.
-   *@param planetModel is the planet model.
-   */
-  public GeoWorld(final PlanetModel planetModel) {
-    super(planetModel);
-    originPoint = new GeoPoint(planetModel.ab, 1.0, 0.0, 0.0);
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    return this;
-  }
-
-  @Override
-  public double getRadius() {
-    return Math.PI;
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    // Totally arbitrary
-    return originPoint;
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return true;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    return false;
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    // Unnecessary
-    //bounds.noLongitudeBound().noTopLatitudeBound().noBottomLatitudeBound();
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    if (path.getEdgePoints().length > 0)
-      // Path is always within the world
-      return WITHIN;
-
-    return OVERLAPS;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    return 0.0;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoWorld))
-      return false;
-    return super.equals(o);
-  }
-
-  @Override
-  public int hashCode() {
-    return super.hashCode();
-  }
-
-  @Override
-  public String toString() {
-    return "GeoWorld: {planetmodel="+planetModel+"}";
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/LatLonBounds.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/LatLonBounds.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/LatLonBounds.java
deleted file mode 100644
index 6478e0c..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/LatLonBounds.java
+++ /dev/null
@@ -1,322 +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.geo3d;
-
-/**
- * An object for accumulating latitude/longitude bounds information.
- *
- * @lucene.experimental
- */
-public class LatLonBounds implements Bounds {
-
-  /** Set to true if no longitude bounds can be stated */
-  protected boolean noLongitudeBound = false;
-  /** Set to true if no top latitude bound can be stated */
-  protected boolean noTopLatitudeBound = false;
-  /** Set to true if no bottom latitude bound can be stated */
-  protected boolean noBottomLatitudeBound = false;
-
-  /** If non-null, the minimum latitude bound */
-  protected Double minLatitude = null;
-  /** If non-null, the maximum latitude bound */
-  protected Double maxLatitude = null;
-
-  // For longitude bounds, this class needs to worry about keeping track of the distinction
-  // between left-side bounds and right-side bounds.  Points are always submitted in pairs
-  // which have a maximum longitude separation of Math.PI.  It's therefore always possible
-  // to determine which point represents a left bound, and which point represents a right
-  // bound.
-  //
-  // The next problem is how to compare two of the same kind of bound, e.g. two left bounds.
-  // We need to keep track of the leftmost longitude of the shape, but since this is a circle,
-  // this is arbitrary.  What we could try to do instead would be to find a pair of (left,right) bounds such
-  // that:
-  // (1) all other bounds are within, and
-  // (2) the left minus right distance is minimized
-  // Unfortunately, there are still shapes that cannot be summarized in this way correctly.
-  // For example. consider a spiral that entirely circles the globe; we might arbitrarily choose
-  // lat/lon bounds that do not in fact circle the globe.
-  //
-  // One way to handle the longitude issue correctly is therefore to stipulate that we
-  // walk the bounds of the shape in some kind of connected order.  Each point or circle is therefore
-  // added in a sequence.  We also need an interior point to make sure we have the right
-  // choice of longitude bounds.  But even with this, we still can't always choose whether the actual shape
-  // goes right or left.
-  //
-  // We can make the specification truly general by submitting the following in order:
-  // addSide(PlaneSide side, Membership... constraints)
-  // ...
-  // This is unambiguous, but I still can't see yet how this would help compute the bounds.  The plane
-  // solution would in general seem to boil down to the same logic that relies on points along the path
-  // to define the shape boundaries.  I guess the one thing that you do know for a bounded edge is that
-  // the endpoints are actually connected.  But it is not clear whether relationship helps in any way.
-  //
-  // In any case, if we specify shapes by a sequence of planes, we should stipulate that multiple sequences
-  // are allowed, provided they progressively tile an area of the sphere that is connected and sequential.
-  // For example, paths do alternating rectangles and circles, in sequence.  Each sequence member is
-  // described by a sequence of planes.  I think it would also be reasonable to insist that the first segment
-  // of a shape overlap or adjoin the previous shape.
-  //
-  // Here's a way to think about it that might help: Traversing every edge should grow the longitude bounds
-  // in the direction of the traversal.  So if the traversal is always known to be less than PI in total longitude
-  // angle, then it is possible to use the endpoints to determine the unambiguous extension of the envelope.
-  // For example, say you are currently at longitude -0.5.  The next point is at longitude PI-0.1.  You could say
-  // that the difference in longitude going one way around would be beter than the distance the other way
-  // around, and therefore the longitude envelope should be extended accordingly.  But in practice, when an
-  // edge goes near a pole and may be inclined as well, the longer longitude change might be the right path, even
-  // if the arc length is short.  So this too doesn't work.
-  //
-  // Given we have a hard time making an exact match, here's the current proposal.  The proposal is a
-  // heuristic, based on the idea that most areas are small compared to the circumference of the globe.
-  // We keep track of the last point we saw, and take each point as it arrives, and compute its longitude.
-  // Then, we have a choice as to which way to expand the envelope: we can expand by going to the left or
-  // to the right.  We choose the direction with the least longitude difference.  (If we aren't sure,
-  // and can recognize that, we can set "unconstrained in longitude".)
-
-  /** If non-null, the left longitude bound */
-  protected Double leftLongitude = null;
-  /** If non-null, the right longitude bound */
-  protected Double rightLongitude = null;
-
-  /** Construct an empty bounds object */
-  public LatLonBounds() {
-  }
-
-  // Accessor methods
-  
-  /** Get maximum latitude, if any.
-   *@return maximum latitude or null.
-   */
-  public Double getMaxLatitude() {
-    return maxLatitude;
-  }
-
-  /** Get minimum latitude, if any.
-   *@return minimum latitude or null.
-   */
-  public Double getMinLatitude() {
-    return minLatitude;
-  }
-
-  /** Get left longitude, if any.
-   *@return left longitude, or null.
-   */
-  public Double getLeftLongitude() {
-    return leftLongitude;
-  }
-
-  /** Get right longitude, if any.
-   *@return right longitude, or null.
-   */
-  public Double getRightLongitude() {
-    return rightLongitude;
-  }
-
-  // Degenerate case check
-  
-  /** Check if there's no longitude bound.
-   *@return true if no longitude bound.
-   */
-  public boolean checkNoLongitudeBound() {
-    return noLongitudeBound;
-  }
-
-  /** Check if there's no top latitude bound.
-   *@return true if no top latitude bound.
-   */
-  public boolean checkNoTopLatitudeBound() {
-    return noTopLatitudeBound;
-  }
-
-  /** Check if there's no bottom latitude bound.
-   *@return true if no bottom latitude bound.
-   */
-  public boolean checkNoBottomLatitudeBound() {
-    return noBottomLatitudeBound;
-  }
-
-  // Modification methods
-  
-  @Override
-  public Bounds addPlane(final PlanetModel planetModel, final Plane plane, final Membership... bounds) {
-    plane.recordBounds(planetModel, this, bounds);
-    return this;
-  }
-
-  @Override
-  public Bounds addHorizontalPlane(final PlanetModel planetModel,
-    final double latitude,
-    final Plane horizontalPlane,
-    final Membership... bounds) {
-    if (!noTopLatitudeBound || !noBottomLatitudeBound) {
-      addLatitudeBound(latitude);
-    }
-    return this;
-  }
-    
-  @Override
-  public Bounds addVerticalPlane(final PlanetModel planetModel,
-    final double longitude,
-    final Plane verticalPlane,
-    final Membership... bounds) {
-    if (!noLongitudeBound) {
-      addLongitudeBound(longitude);
-    }
-    return this;
-  }
-
-  @Override
-  public Bounds isWide() {
-    return noLongitudeBound();
-  }
-
-  @Override
-  public Bounds addXValue(final GeoPoint point) {
-    if (!noLongitudeBound) {
-      // Get a longitude value
-      addLongitudeBound(point.getLongitude());
-    }
-    return this;
-  }
-
-  @Override
-  public Bounds addYValue(final GeoPoint point) {
-    if (!noLongitudeBound) {
-      // Get a longitude value
-      addLongitudeBound(point.getLongitude());
-    }
-    return this;
-  }
-
-  @Override
-  public Bounds addZValue(final GeoPoint point) {
-    if (!noTopLatitudeBound || !noBottomLatitudeBound) {
-      // Compute a latitude value
-      double latitude = point.getLatitude();
-      addLatitudeBound(latitude);
-    }
-    return this;
-  }
-
-  @Override
-  public Bounds addPoint(GeoPoint point) {
-    if (!noLongitudeBound) {
-      // Get a longitude value
-      addLongitudeBound(point.getLongitude());
-    }
-    if (!noTopLatitudeBound || !noBottomLatitudeBound) {
-      // Compute a latitude value
-      addLatitudeBound(point.getLatitude());
-    }
-    return this;
-  }
-  
-  @Override
-  public Bounds noLongitudeBound() {
-    noLongitudeBound = true;
-    leftLongitude = null;
-    rightLongitude = null;
-    return this;
-  }
-
-  @Override
-  public Bounds noTopLatitudeBound() {
-    noTopLatitudeBound = true;
-    maxLatitude = null;
-    return this;
-  }
-
-  @Override
-  public Bounds noBottomLatitudeBound() {
-    noBottomLatitudeBound = true;
-    minLatitude = null;
-    return this;
-  }
-
-  // Protected methods
-  
-  /** Update latitude bound.
-   *@param latitude is the latitude.
-   */
-  protected void addLatitudeBound(double latitude) {
-    if (!noTopLatitudeBound && (maxLatitude == null || latitude > maxLatitude))
-      maxLatitude = latitude;
-    if (!noBottomLatitudeBound && (minLatitude == null || latitude < minLatitude))
-      minLatitude = latitude;
-  }
-
-  /** Update longitude bound.
-   *@param longitude is the new longitude value.
-   */
-  protected void addLongitudeBound(double longitude) {
-    // If this point is within the current bounds, we're done; otherwise
-    // expand one side or the other.
-    if (leftLongitude == null && rightLongitude == null) {
-      leftLongitude = longitude;
-      rightLongitude = longitude;
-    } else {
-      // Compute whether we're to the right of the left value.  But the left value may be greater than
-      // the right value.
-      double currentLeftLongitude = leftLongitude;
-      double currentRightLongitude = rightLongitude;
-      if (currentRightLongitude < currentLeftLongitude)
-        currentRightLongitude += 2.0 * Math.PI;
-      // We have a range to look at that's going in the right way.
-      // Now, do the same trick with the computed longitude.
-      if (longitude < currentLeftLongitude)
-        longitude += 2.0 * Math.PI;
-
-      if (longitude < currentLeftLongitude || longitude > currentRightLongitude) {
-        // Outside of current bounds.  Consider carefully how we'll expand.
-        double leftExtensionAmt;
-        double rightExtensionAmt;
-        if (longitude < currentLeftLongitude) {
-          leftExtensionAmt = currentLeftLongitude - longitude;
-        } else {
-          leftExtensionAmt = currentLeftLongitude + 2.0 * Math.PI - longitude;
-        }
-        if (longitude > currentRightLongitude) {
-          rightExtensionAmt = longitude - currentRightLongitude;
-        } else {
-          rightExtensionAmt = longitude + 2.0 * Math.PI - currentRightLongitude;
-        }
-        if (leftExtensionAmt < rightExtensionAmt) {
-          currentLeftLongitude = leftLongitude - leftExtensionAmt;
-          while (currentLeftLongitude <= -Math.PI) {
-            currentLeftLongitude += 2.0 * Math.PI;
-          }
-          leftLongitude = currentLeftLongitude;
-        } else {
-          currentRightLongitude = rightLongitude + rightExtensionAmt;
-          while (currentRightLongitude > Math.PI) {
-            currentRightLongitude -= 2.0 * Math.PI;
-          }
-          rightLongitude = currentRightLongitude;
-        }
-      }
-    }
-    double testRightLongitude = rightLongitude;
-    if (testRightLongitude < leftLongitude)
-      testRightLongitude += Math.PI * 2.0;
-    if (testRightLongitude - leftLongitude >= Math.PI) {
-      noLongitudeBound = true;
-      leftLongitude = null;
-      rightLongitude = null;
-    }
-  }
-
-}


[06/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 0093e26)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideSouthRectangle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideSouthRectangle.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideSouthRectangle.java
new file mode 100644
index 0000000..da9799a
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWideSouthRectangle.java
@@ -0,0 +1,284 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Bounding box wider than PI but limited on three sides (top lat,
+ * left lon, right lon).
+ *
+ * @lucene.internal
+ */
+public class GeoWideSouthRectangle extends GeoBaseBBox {
+  /** Top latitude of rect */
+  protected final double topLat;
+  /** Left longitude of rect */
+  protected final double leftLon;
+  /** Right longitude of rect */
+  protected final double rightLon;
+
+  /** Cosine of middle latitude */
+  protected final double cosMiddleLat;
+
+  /** Upper left hand corner */
+  protected final GeoPoint ULHC;
+  /** Upper right hand corner */
+  protected final GeoPoint URHC;
+
+  /** The top plane */
+  protected final SidedPlane topPlane;
+  /** The left plane */
+  protected final SidedPlane leftPlane;
+  /** The right plane */
+  protected final SidedPlane rightPlane;
+
+  /** Notable points for top plane */
+  protected final GeoPoint[] topPlanePoints;
+  /** Notable points for left plane */
+  protected final GeoPoint[] leftPlanePoints;
+  /** Notable points for right plane */
+  protected final GeoPoint[] rightPlanePoints;
+
+  /** Center point */
+  protected final GeoPoint centerPoint;
+
+  /** Left/right bounds */
+  protected final EitherBound eitherBound;
+
+  /** A point on the edge */
+  protected final GeoPoint[] edgePoints;
+
+  /**
+   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}.
+   * Horizontal angle must be greater than or equal to PI.
+   */
+  public GeoWideSouthRectangle(final PlanetModel planetModel, final double topLat, final double leftLon, double rightLon) {
+    super(planetModel);
+    // Argument checking
+    if (topLat > Math.PI * 0.5 || topLat < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Top latitude out of range");
+    if (leftLon < -Math.PI || leftLon > Math.PI)
+      throw new IllegalArgumentException("Left longitude out of range");
+    if (rightLon < -Math.PI || rightLon > Math.PI)
+      throw new IllegalArgumentException("Right longitude out of range");
+    double extent = rightLon - leftLon;
+    if (extent < 0.0) {
+      extent += 2.0 * Math.PI;
+    }
+    if (extent < Math.PI)
+      throw new IllegalArgumentException("Width of rectangle too small");
+
+    this.topLat = topLat;
+    this.leftLon = leftLon;
+    this.rightLon = rightLon;
+
+    final double sinTopLat = Math.sin(topLat);
+    final double cosTopLat = Math.cos(topLat);
+    final double sinLeftLon = Math.sin(leftLon);
+    final double cosLeftLon = Math.cos(leftLon);
+    final double sinRightLon = Math.sin(rightLon);
+    final double cosRightLon = Math.cos(rightLon);
+
+    // Now build the four points
+    this.ULHC = new GeoPoint(planetModel, sinTopLat, sinLeftLon, cosTopLat, cosLeftLon, topLat, leftLon);
+    this.URHC = new GeoPoint(planetModel, sinTopLat, sinRightLon, cosTopLat, cosRightLon, topLat, rightLon);
+
+    final double middleLat = (topLat - Math.PI * 0.5) * 0.5;
+    final double sinMiddleLat = Math.sin(middleLat);
+    this.cosMiddleLat = Math.cos(middleLat);
+    // Normalize
+    while (leftLon > rightLon) {
+      rightLon += Math.PI * 2.0;
+    }
+    final double middleLon = (leftLon + rightLon) * 0.5;
+    final double sinMiddleLon = Math.sin(middleLon);
+    final double cosMiddleLon = Math.cos(middleLon);
+
+    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinMiddleLon, cosMiddleLat, cosMiddleLon);
+
+    this.topPlane = new SidedPlane(centerPoint, planetModel, sinTopLat);
+    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
+    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
+
+    this.topPlanePoints = new GeoPoint[]{ULHC, URHC};
+    this.leftPlanePoints = new GeoPoint[]{ULHC, planetModel.SOUTH_POLE};
+    this.rightPlanePoints = new GeoPoint[]{URHC, planetModel.SOUTH_POLE};
+
+    this.eitherBound = new EitherBound();
+    
+    this.edgePoints = new GeoPoint[]{planetModel.SOUTH_POLE};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    final double newTopLat = topLat + angle;
+    final double newBottomLat = -Math.PI * 0.5;
+    // Figuring out when we escalate to a special case requires some prefiguring
+    double currentLonSpan = rightLon - leftLon;
+    if (currentLonSpan < 0.0)
+      currentLonSpan += Math.PI * 2.0;
+    double newLeftLon = leftLon - angle;
+    double newRightLon = rightLon + angle;
+    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
+      newLeftLon = -Math.PI;
+      newRightLon = Math.PI;
+    }
+    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return topPlane.isWithin(x, y, z) &&
+        (leftPlane.isWithin(x, y, z) ||
+            rightPlane.isWithin(x, y, z));
+  }
+
+  @Override
+  public double getRadius() {
+    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
+    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
+    // the distance to the right or left edge from the center.
+    final double centerAngle = (rightLon - (rightLon + leftLon) * 0.5) * cosMiddleLat;
+    final double topAngle = centerPoint.arcDistance(URHC);
+    return Math.max(centerAngle, topAngle);
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    return centerPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    // Right and left bounds are essentially independent hemispheres; crossing into the wrong part of one
+    // requires crossing into the right part of the other.  So intersection can ignore the left/right bounds.
+    return p.intersects(planetModel, topPlane, notablePoints, topPlanePoints, bounds, eitherBound) ||
+        p.intersects(planetModel, leftPlane, notablePoints, leftPlanePoints, bounds, topPlane) ||
+        p.intersects(planetModel, rightPlane, notablePoints, rightPlanePoints, bounds, topPlane);
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    bounds.isWide()
+      .addHorizontalPlane(planetModel, topLat, topPlane, eitherBound)
+      .addVerticalPlane(planetModel, rightLon, rightPlane, topPlane)
+      .addVerticalPlane(planetModel, leftLon, leftPlane, topPlane)
+      .addPoint(ULHC).addPoint(URHC).addPoint(planetModel.SOUTH_POLE);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    //System.err.println(this+" comparing to "+path);
+    final int insideRectangle = isShapeInsideBBox(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some inside");
+      return OVERLAPS;
+    }
+
+    final boolean insideShape = path.isWithin(planetModel.SOUTH_POLE);
+
+    if (insideRectangle == ALL_INSIDE && insideShape) {
+      //System.err.println(" both inside each other");
+      return OVERLAPS;
+    }
+
+    if (path.intersects(topPlane, topPlanePoints, eitherBound) ||
+        path.intersects(leftPlane, leftPlanePoints, topPlane) ||
+        path.intersects(rightPlane, rightPlanePoints, topPlane)) {
+      //System.err.println(" edges intersect");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      //System.err.println(" shape inside rectangle");
+      return WITHIN;
+    }
+
+    if (insideShape) {
+      //System.err.println(" rectangle inside shape");
+      return CONTAINS;
+    }
+
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    final double topDistance = distanceStyle.computeDistance(planetModel, topPlane, x,y,z, eitherBound);
+    // Because the rectangle exceeds 180 degrees, it is safe to compute the horizontally 
+    // unbounded distance to both the left and the right and only take the minimum of the two.
+    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, topPlane);
+    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, topPlane);
+    
+    final double ULHCDistance = distanceStyle.computeDistance(ULHC, x,y,z);
+    final double URHCDistance = distanceStyle.computeDistance(URHC, x,y,z);
+    
+    return Math.min(
+      Math.min(
+        topDistance,
+        Math.min(leftDistance, rightDistance)),
+      Math.min(ULHCDistance, URHCDistance));
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoWideSouthRectangle))
+      return false;
+    GeoWideSouthRectangle other = (GeoWideSouthRectangle) o;
+    return super.equals(o) && other.ULHC.equals(ULHC) && other.URHC.equals(URHC);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + ULHC.hashCode();
+    result = 31 * result + URHC.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoWideSouthRectangle: {planetmodel="+planetModel+", toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
+  }
+
+  /** Membership implementation representing width more than 180.
+   */
+  protected class EitherBound implements Membership {
+    /** Constructor.
+     */
+    public EitherBound() {
+    }
+
+    @Override
+    public boolean isWithin(final Vector v) {
+      return leftPlane.isWithin(v) || rightPlane.isWithin(v);
+    }
+
+    @Override
+    public boolean isWithin(final double x, final double y, final double z) {
+      return leftPlane.isWithin(x, y, z) || rightPlane.isWithin(x, y, z);
+    }
+  }
+}
+  
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWorld.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWorld.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWorld.java
new file mode 100755
index 0000000..25bdc96
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWorld.java
@@ -0,0 +1,106 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Bounding box including the entire world.
+ *
+ * @lucene.internal
+ */
+public class GeoWorld extends GeoBaseBBox {
+  /** No points on the edge of the shape */
+  protected final static GeoPoint[] edgePoints = new GeoPoint[0];
+  /** Point in the middle of the world */
+  protected final GeoPoint originPoint;
+  
+  /** Constructor.
+   *@param planetModel is the planet model.
+   */
+  public GeoWorld(final PlanetModel planetModel) {
+    super(planetModel);
+    originPoint = new GeoPoint(planetModel.ab, 1.0, 0.0, 0.0);
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    return this;
+  }
+
+  @Override
+  public double getRadius() {
+    return Math.PI;
+  }
+
+  @Override
+  public GeoPoint getCenter() {
+    // Totally arbitrary
+    return originPoint;
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return true;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return false;
+  }
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    // Unnecessary
+    //bounds.noLongitudeBound().noTopLatitudeBound().noBottomLatitudeBound();
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    if (path.getEdgePoints().length > 0)
+      // Path is always within the world
+      return WITHIN;
+
+    return OVERLAPS;
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    return 0.0;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoWorld))
+      return false;
+    return super.equals(o);
+  }
+
+  @Override
+  public int hashCode() {
+    return super.hashCode();
+  }
+
+  @Override
+  public String toString() {
+    return "GeoWorld: {planetmodel="+planetModel+"}";
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/LatLonBounds.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/LatLonBounds.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/LatLonBounds.java
new file mode 100644
index 0000000..627fdae
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/LatLonBounds.java
@@ -0,0 +1,322 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * An object for accumulating latitude/longitude bounds information.
+ *
+ * @lucene.experimental
+ */
+public class LatLonBounds implements Bounds {
+
+  /** Set to true if no longitude bounds can be stated */
+  protected boolean noLongitudeBound = false;
+  /** Set to true if no top latitude bound can be stated */
+  protected boolean noTopLatitudeBound = false;
+  /** Set to true if no bottom latitude bound can be stated */
+  protected boolean noBottomLatitudeBound = false;
+
+  /** If non-null, the minimum latitude bound */
+  protected Double minLatitude = null;
+  /** If non-null, the maximum latitude bound */
+  protected Double maxLatitude = null;
+
+  // For longitude bounds, this class needs to worry about keeping track of the distinction
+  // between left-side bounds and right-side bounds.  Points are always submitted in pairs
+  // which have a maximum longitude separation of Math.PI.  It's therefore always possible
+  // to determine which point represents a left bound, and which point represents a right
+  // bound.
+  //
+  // The next problem is how to compare two of the same kind of bound, e.g. two left bounds.
+  // We need to keep track of the leftmost longitude of the shape, but since this is a circle,
+  // this is arbitrary.  What we could try to do instead would be to find a pair of (left,right) bounds such
+  // that:
+  // (1) all other bounds are within, and
+  // (2) the left minus right distance is minimized
+  // Unfortunately, there are still shapes that cannot be summarized in this way correctly.
+  // For example. consider a spiral that entirely circles the globe; we might arbitrarily choose
+  // lat/lon bounds that do not in fact circle the globe.
+  //
+  // One way to handle the longitude issue correctly is therefore to stipulate that we
+  // walk the bounds of the shape in some kind of connected order.  Each point or circle is therefore
+  // added in a sequence.  We also need an interior point to make sure we have the right
+  // choice of longitude bounds.  But even with this, we still can't always choose whether the actual shape
+  // goes right or left.
+  //
+  // We can make the specification truly general by submitting the following in order:
+  // addSide(PlaneSide side, Membership... constraints)
+  // ...
+  // This is unambiguous, but I still can't see yet how this would help compute the bounds.  The plane
+  // solution would in general seem to boil down to the same logic that relies on points along the path
+  // to define the shape boundaries.  I guess the one thing that you do know for a bounded edge is that
+  // the endpoints are actually connected.  But it is not clear whether relationship helps in any way.
+  //
+  // In any case, if we specify shapes by a sequence of planes, we should stipulate that multiple sequences
+  // are allowed, provided they progressively tile an area of the sphere that is connected and sequential.
+  // For example, paths do alternating rectangles and circles, in sequence.  Each sequence member is
+  // described by a sequence of planes.  I think it would also be reasonable to insist that the first segment
+  // of a shape overlap or adjoin the previous shape.
+  //
+  // Here's a way to think about it that might help: Traversing every edge should grow the longitude bounds
+  // in the direction of the traversal.  So if the traversal is always known to be less than PI in total longitude
+  // angle, then it is possible to use the endpoints to determine the unambiguous extension of the envelope.
+  // For example, say you are currently at longitude -0.5.  The next point is at longitude PI-0.1.  You could say
+  // that the difference in longitude going one way around would be beter than the distance the other way
+  // around, and therefore the longitude envelope should be extended accordingly.  But in practice, when an
+  // edge goes near a pole and may be inclined as well, the longer longitude change might be the right path, even
+  // if the arc length is short.  So this too doesn't work.
+  //
+  // Given we have a hard time making an exact match, here's the current proposal.  The proposal is a
+  // heuristic, based on the idea that most areas are small compared to the circumference of the globe.
+  // We keep track of the last point we saw, and take each point as it arrives, and compute its longitude.
+  // Then, we have a choice as to which way to expand the envelope: we can expand by going to the left or
+  // to the right.  We choose the direction with the least longitude difference.  (If we aren't sure,
+  // and can recognize that, we can set "unconstrained in longitude".)
+
+  /** If non-null, the left longitude bound */
+  protected Double leftLongitude = null;
+  /** If non-null, the right longitude bound */
+  protected Double rightLongitude = null;
+
+  /** Construct an empty bounds object */
+  public LatLonBounds() {
+  }
+
+  // Accessor methods
+  
+  /** Get maximum latitude, if any.
+   *@return maximum latitude or null.
+   */
+  public Double getMaxLatitude() {
+    return maxLatitude;
+  }
+
+  /** Get minimum latitude, if any.
+   *@return minimum latitude or null.
+   */
+  public Double getMinLatitude() {
+    return minLatitude;
+  }
+
+  /** Get left longitude, if any.
+   *@return left longitude, or null.
+   */
+  public Double getLeftLongitude() {
+    return leftLongitude;
+  }
+
+  /** Get right longitude, if any.
+   *@return right longitude, or null.
+   */
+  public Double getRightLongitude() {
+    return rightLongitude;
+  }
+
+  // Degenerate case check
+  
+  /** Check if there's no longitude bound.
+   *@return true if no longitude bound.
+   */
+  public boolean checkNoLongitudeBound() {
+    return noLongitudeBound;
+  }
+
+  /** Check if there's no top latitude bound.
+   *@return true if no top latitude bound.
+   */
+  public boolean checkNoTopLatitudeBound() {
+    return noTopLatitudeBound;
+  }
+
+  /** Check if there's no bottom latitude bound.
+   *@return true if no bottom latitude bound.
+   */
+  public boolean checkNoBottomLatitudeBound() {
+    return noBottomLatitudeBound;
+  }
+
+  // Modification methods
+  
+  @Override
+  public Bounds addPlane(final PlanetModel planetModel, final Plane plane, final Membership... bounds) {
+    plane.recordBounds(planetModel, this, bounds);
+    return this;
+  }
+
+  @Override
+  public Bounds addHorizontalPlane(final PlanetModel planetModel,
+    final double latitude,
+    final Plane horizontalPlane,
+    final Membership... bounds) {
+    if (!noTopLatitudeBound || !noBottomLatitudeBound) {
+      addLatitudeBound(latitude);
+    }
+    return this;
+  }
+    
+  @Override
+  public Bounds addVerticalPlane(final PlanetModel planetModel,
+    final double longitude,
+    final Plane verticalPlane,
+    final Membership... bounds) {
+    if (!noLongitudeBound) {
+      addLongitudeBound(longitude);
+    }
+    return this;
+  }
+
+  @Override
+  public Bounds isWide() {
+    return noLongitudeBound();
+  }
+
+  @Override
+  public Bounds addXValue(final GeoPoint point) {
+    if (!noLongitudeBound) {
+      // Get a longitude value
+      addLongitudeBound(point.getLongitude());
+    }
+    return this;
+  }
+
+  @Override
+  public Bounds addYValue(final GeoPoint point) {
+    if (!noLongitudeBound) {
+      // Get a longitude value
+      addLongitudeBound(point.getLongitude());
+    }
+    return this;
+  }
+
+  @Override
+  public Bounds addZValue(final GeoPoint point) {
+    if (!noTopLatitudeBound || !noBottomLatitudeBound) {
+      // Compute a latitude value
+      double latitude = point.getLatitude();
+      addLatitudeBound(latitude);
+    }
+    return this;
+  }
+
+  @Override
+  public Bounds addPoint(GeoPoint point) {
+    if (!noLongitudeBound) {
+      // Get a longitude value
+      addLongitudeBound(point.getLongitude());
+    }
+    if (!noTopLatitudeBound || !noBottomLatitudeBound) {
+      // Compute a latitude value
+      addLatitudeBound(point.getLatitude());
+    }
+    return this;
+  }
+  
+  @Override
+  public Bounds noLongitudeBound() {
+    noLongitudeBound = true;
+    leftLongitude = null;
+    rightLongitude = null;
+    return this;
+  }
+
+  @Override
+  public Bounds noTopLatitudeBound() {
+    noTopLatitudeBound = true;
+    maxLatitude = null;
+    return this;
+  }
+
+  @Override
+  public Bounds noBottomLatitudeBound() {
+    noBottomLatitudeBound = true;
+    minLatitude = null;
+    return this;
+  }
+
+  // Protected methods
+  
+  /** Update latitude bound.
+   *@param latitude is the latitude.
+   */
+  protected void addLatitudeBound(double latitude) {
+    if (!noTopLatitudeBound && (maxLatitude == null || latitude > maxLatitude))
+      maxLatitude = latitude;
+    if (!noBottomLatitudeBound && (minLatitude == null || latitude < minLatitude))
+      minLatitude = latitude;
+  }
+
+  /** Update longitude bound.
+   *@param longitude is the new longitude value.
+   */
+  protected void addLongitudeBound(double longitude) {
+    // If this point is within the current bounds, we're done; otherwise
+    // expand one side or the other.
+    if (leftLongitude == null && rightLongitude == null) {
+      leftLongitude = longitude;
+      rightLongitude = longitude;
+    } else {
+      // Compute whether we're to the right of the left value.  But the left value may be greater than
+      // the right value.
+      double currentLeftLongitude = leftLongitude;
+      double currentRightLongitude = rightLongitude;
+      if (currentRightLongitude < currentLeftLongitude)
+        currentRightLongitude += 2.0 * Math.PI;
+      // We have a range to look at that's going in the right way.
+      // Now, do the same trick with the computed longitude.
+      if (longitude < currentLeftLongitude)
+        longitude += 2.0 * Math.PI;
+
+      if (longitude < currentLeftLongitude || longitude > currentRightLongitude) {
+        // Outside of current bounds.  Consider carefully how we'll expand.
+        double leftExtensionAmt;
+        double rightExtensionAmt;
+        if (longitude < currentLeftLongitude) {
+          leftExtensionAmt = currentLeftLongitude - longitude;
+        } else {
+          leftExtensionAmt = currentLeftLongitude + 2.0 * Math.PI - longitude;
+        }
+        if (longitude > currentRightLongitude) {
+          rightExtensionAmt = longitude - currentRightLongitude;
+        } else {
+          rightExtensionAmt = longitude + 2.0 * Math.PI - currentRightLongitude;
+        }
+        if (leftExtensionAmt < rightExtensionAmt) {
+          currentLeftLongitude = leftLongitude - leftExtensionAmt;
+          while (currentLeftLongitude <= -Math.PI) {
+            currentLeftLongitude += 2.0 * Math.PI;
+          }
+          leftLongitude = currentLeftLongitude;
+        } else {
+          currentRightLongitude = rightLongitude + rightExtensionAmt;
+          while (currentRightLongitude > Math.PI) {
+            currentRightLongitude -= 2.0 * Math.PI;
+          }
+          rightLongitude = currentRightLongitude;
+        }
+      }
+    }
+    double testRightLongitude = rightLongitude;
+    if (testRightLongitude < leftLongitude)
+      testRightLongitude += Math.PI * 2.0;
+    if (testRightLongitude - leftLongitude >= Math.PI) {
+      noLongitudeBound = true;
+      leftLongitude = null;
+      rightLongitude = null;
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/LinearDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/LinearDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/LinearDistance.java
new file mode 100644
index 0000000..0c89a16
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/LinearDistance.java
@@ -0,0 +1,56 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Linear distance computation style.
+ *
+ * @lucene.experimental
+ */
+public class LinearDistance implements DistanceStyle {
+  
+  /** A convenient instance */
+  public final static LinearDistance INSTANCE = new LinearDistance();
+  
+  /** Constructor.
+   */
+  public LinearDistance() {
+  }
+  
+  @Override
+  public double computeDistance(final GeoPoint point1, final GeoPoint point2) {
+    return point1.linearDistance(point2);
+  }
+  
+  @Override
+  public double computeDistance(final GeoPoint point1, final double x2, final double y2, final double z2) {
+    return point1.linearDistance(x2,y2,z2);
+  }
+
+  @Override
+  public double computeDistance(final PlanetModel planetModel, final Plane plane, final GeoPoint point, final Membership... bounds) {
+    return plane.linearDistance(planetModel, point, bounds);
+  }
+  
+  @Override
+  public double computeDistance(final PlanetModel planetModel, final Plane plane, final double x, final double y, final double z, final Membership... bounds) {
+    return plane.linearDistance(planetModel, x,y,z, bounds);
+  }
+
+}
+
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/LinearSquaredDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/LinearSquaredDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/LinearSquaredDistance.java
new file mode 100644
index 0000000..3fc37da
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/LinearSquaredDistance.java
@@ -0,0 +1,56 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Linear squared distance computation style.
+ *
+ * @lucene.experimental
+ */
+public class LinearSquaredDistance implements DistanceStyle {
+  
+  /** A convenient instance */
+  public final static LinearSquaredDistance INSTANCE = new LinearSquaredDistance();
+  
+  /** Constructor.
+   */
+  public LinearSquaredDistance() {
+  }
+  
+  @Override
+  public double computeDistance(final GeoPoint point1, final GeoPoint point2) {
+    return point1.linearDistanceSquared(point2);
+  }
+  
+  @Override
+  public double computeDistance(final GeoPoint point1, final double x2, final double y2, final double z2) {
+    return point1.linearDistanceSquared(x2,y2,z2);
+  }
+
+  @Override
+  public double computeDistance(final PlanetModel planetModel, final Plane plane, final GeoPoint point, final Membership... bounds) {
+    return plane.linearDistanceSquared(planetModel, point, bounds);
+  }
+  
+  @Override
+  public double computeDistance(final PlanetModel planetModel, final Plane plane, final double x, final double y, final double z, final Membership... bounds) {
+    return plane.linearDistanceSquared(planetModel, x,y,z, bounds);
+  }
+
+}
+
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Membership.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Membership.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Membership.java
new file mode 100755
index 0000000..0cf6ff0
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Membership.java
@@ -0,0 +1,46 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Implemented by Geo3D shapes that can calculate if a point is within it or not.
+ *
+ * @lucene.experimental
+ */
+public interface Membership {
+
+  /**
+   * Check if a point is within this shape.
+   *
+   * @param point is the point to check.
+   * @return true if the point is within this shape
+   */
+  public default boolean isWithin(final Vector point) {
+    return isWithin(point.x, point.y, point.z);
+  }
+
+  /**
+   * Check if a point is within this shape.
+   *
+   * @param x is x coordinate of point to check.
+   * @param y is y coordinate of point to check.
+   * @param z is z coordinate of point to check.
+   * @return true if the point is within this shape
+   */
+  public boolean isWithin(final double x, final double y, final double z);
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/NormalDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/NormalDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/NormalDistance.java
new file mode 100644
index 0000000..50b2c7f
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/NormalDistance.java
@@ -0,0 +1,56 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Normal distance computation style.
+ *
+ * @lucene.experimental
+ */
+public class NormalDistance implements DistanceStyle {
+  
+  /** A convenient instance */
+  public final static NormalDistance INSTANCE = new NormalDistance();
+  
+  /** Constructor.
+   */
+  public NormalDistance() {
+  }
+  
+  @Override
+  public double computeDistance(final GeoPoint point1, final GeoPoint point2) {
+    return point1.normalDistance(point2);
+  }
+  
+  @Override
+  public double computeDistance(final GeoPoint point1, final double x2, final double y2, final double z2) {
+    return point1.normalDistance(x2,y2,z2);
+  }
+
+  @Override
+  public double computeDistance(final PlanetModel planetModel, final Plane plane, final GeoPoint point, final Membership... bounds) {
+    return plane.normalDistance(point, bounds);
+  }
+  
+  @Override
+  public double computeDistance(final PlanetModel planetModel, final Plane plane, final double x, final double y, final double z, final Membership... bounds) {
+    return plane.normalDistance(x,y,z, bounds);
+  }
+
+}
+
+

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/NormalSquaredDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/NormalSquaredDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/NormalSquaredDistance.java
new file mode 100644
index 0000000..a355d09
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/NormalSquaredDistance.java
@@ -0,0 +1,56 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Normal squared distance computation style.
+ *
+ * @lucene.experimental
+ */
+public class NormalSquaredDistance implements DistanceStyle {
+  
+  /** A convenient instance */
+  public final static NormalSquaredDistance INSTANCE = new NormalSquaredDistance();
+  
+  /** Constructor.
+   */
+  public NormalSquaredDistance() {
+  }
+  
+  @Override
+  public double computeDistance(final GeoPoint point1, final GeoPoint point2) {
+    return point1.normalDistanceSquared(point2);
+  }
+  
+  @Override
+  public double computeDistance(final GeoPoint point1, final double x2, final double y2, final double z2) {
+    return point1.normalDistanceSquared(x2,y2,z2);
+  }
+
+  @Override
+  public double computeDistance(final PlanetModel planetModel, final Plane plane, final GeoPoint point, final Membership... bounds) {
+    return plane.normalDistanceSquared(point, bounds);
+  }
+  
+  @Override
+  public double computeDistance(final PlanetModel planetModel, final Plane plane, final double x, final double y, final double z, final Membership... bounds) {
+    return plane.normalDistanceSquared(x,y,z, bounds);
+  }
+
+}
+
+


[14/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 0093e26)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPath.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPath.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPath.java
deleted file mode 100755
index bc5b9cf..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPath.java
+++ /dev/null
@@ -1,797 +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.geo3d;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * GeoShape representing a path across the surface of the globe,
- * with a specified half-width.  Path is described by a series of points.
- * Distances are measured from the starting point along the path, and then at right
- * angles to the path.
- *
- * @lucene.experimental
- */
-public class GeoPath extends GeoBaseDistanceShape {
-  /** The cutoff angle (width) */
-  protected final double cutoffAngle;
-
-  /** Sine of cutoff angle */
-  protected final double sinAngle;
-  /** Cosine of cutoff angle */
-  protected final double cosAngle;
-
-  /** The original list of path points */
-  protected final List<GeoPoint> points = new ArrayList<GeoPoint>();
-  
-  /** A list of SegmentEndpoints */
-  protected List<SegmentEndpoint> endPoints;
-  /** A list of PathSegments */
-  protected List<PathSegment> segments;
-
-  /** A point on the edge */
-  protected GeoPoint[] edgePoints;
-
-  /** Set to true if path has been completely constructed */
-  protected boolean isDone = false;
-  
-  /** Constructor.
-   *@param planetModel is the planet model.
-   *@param maxCutoffAngle is the width of the path, measured as an angle.
-   *@param pathPoints are the points in the path.
-   */
-  public GeoPath(final PlanetModel planetModel, final double maxCutoffAngle, final GeoPoint[] pathPoints) {
-    this(planetModel, maxCutoffAngle);
-    Collections.addAll(points, pathPoints);
-    done();
-  }
-  
-  /** Piece-wise constructor.  Use in conjunction with addPoint() and done().
-   *@param planetModel is the planet model.
-   *@param maxCutoffAngle is the width of the path, measured as an angle.
-   */
-  public GeoPath(final PlanetModel planetModel, final double maxCutoffAngle) {
-    super(planetModel);
-    if (maxCutoffAngle <= 0.0 || maxCutoffAngle > Math.PI * 0.5)
-      throw new IllegalArgumentException("Cutoff angle out of bounds");
-    this.cutoffAngle = maxCutoffAngle;
-    this.cosAngle = Math.cos(maxCutoffAngle);
-    this.sinAngle = Math.sin(maxCutoffAngle);
-  }
-
-  /** Add a point to the path.
-   *@param lat is the latitude of the point.
-   *@param lon is the longitude of the point.
-   */
-  public void addPoint(final double lat, final double lon) {
-    if (isDone)
-      throw new IllegalStateException("Can't call addPoint() if done() already called");
-    points.add(new GeoPoint(planetModel, lat, lon));
-  }
-  
-  /** Complete the path.
-   */
-  public void done() {
-    if (isDone)
-      throw new IllegalStateException("Can't call done() twice");
-    if (points.size() == 0)
-      throw new IllegalArgumentException("Path must have at least one point");
-    isDone = true;
-
-    endPoints = new ArrayList<>(points.size());
-    segments = new ArrayList<>(points.size());
-    // Compute an offset to use for all segments.  This will be based on the minimum magnitude of
-    // the entire ellipsoid.
-    final double cutoffOffset = this.sinAngle * planetModel.getMinimumMagnitude();
-    
-    // First, build all segments.  We'll then go back and build corresponding segment endpoints.
-    GeoPoint lastPoint = null;
-    for (final GeoPoint end : points) {
-      if (lastPoint != null) {
-        final Plane normalizedConnectingPlane = new Plane(lastPoint, end);
-        if (normalizedConnectingPlane == null) {
-          continue;
-        }
-        segments.add(new PathSegment(planetModel, lastPoint, end, normalizedConnectingPlane, cutoffOffset));
-      }
-      lastPoint = end;
-    }
-    
-    if (segments.size() == 0) {
-      // Simple circle
-      double lat = points.get(0).getLatitude();
-      double lon = points.get(0).getLongitude();
-      // Compute two points on the circle, with the right angle from the center.  We'll use these
-      // to obtain the perpendicular plane to the circle.
-      double upperLat = lat + cutoffAngle;
-      double upperLon = lon;
-      if (upperLat > Math.PI * 0.5) {
-        upperLon += Math.PI;
-        if (upperLon > Math.PI)
-          upperLon -= 2.0 * Math.PI;
-        upperLat = Math.PI - upperLat;
-      }
-      double lowerLat = lat - cutoffAngle;
-      double lowerLon = lon;
-      if (lowerLat < -Math.PI * 0.5) {
-        lowerLon += Math.PI;
-        if (lowerLon > Math.PI)
-          lowerLon -= 2.0 * Math.PI;
-        lowerLat = -Math.PI - lowerLat;
-      }
-      final GeoPoint upperPoint = new GeoPoint(planetModel, upperLat, upperLon);
-      final GeoPoint lowerPoint = new GeoPoint(planetModel, lowerLat, lowerLon);
-      final GeoPoint point = points.get(0);
-      
-      // Construct normal plane
-      final Plane normalPlane = Plane.constructNormalizedZPlane(upperPoint, lowerPoint, point);
-
-      final SegmentEndpoint onlyEndpoint = new SegmentEndpoint(point, normalPlane, upperPoint, lowerPoint);
-      endPoints.add(onlyEndpoint);
-      this.edgePoints = new GeoPoint[]{onlyEndpoint.circlePlane.getSampleIntersectionPoint(planetModel, normalPlane)};
-      return;
-    }
-    
-    // Create segment endpoints.  Use an appropriate constructor for the start and end of the path.
-    for (int i = 0; i < segments.size(); i++) {
-      final PathSegment currentSegment = segments.get(i);
-      
-      if (i == 0) {
-        // Starting endpoint
-        final SegmentEndpoint startEndpoint = new SegmentEndpoint(currentSegment.start, 
-          currentSegment.startCutoffPlane, currentSegment.ULHC, currentSegment.LLHC);
-        endPoints.add(startEndpoint);
-        this.edgePoints = new GeoPoint[]{currentSegment.ULHC};
-        continue;
-      }
-      
-      // General intersection case
-      final PathSegment prevSegment = segments.get(i-1);
-      // We construct four separate planes, and evaluate which one includes all interior points with least overlap
-      final SidedPlane candidate1 = SidedPlane.constructNormalizedThreePointSidedPlane(currentSegment.start, prevSegment.URHC, currentSegment.ULHC, currentSegment.LLHC);
-      final SidedPlane candidate2 = SidedPlane.constructNormalizedThreePointSidedPlane(currentSegment.start, currentSegment.ULHC, currentSegment.LLHC, prevSegment.LRHC);
-      final SidedPlane candidate3 = SidedPlane.constructNormalizedThreePointSidedPlane(currentSegment.start, currentSegment.LLHC, prevSegment.LRHC, prevSegment.URHC);
-      final SidedPlane candidate4 = SidedPlane.constructNormalizedThreePointSidedPlane(currentSegment.start, prevSegment.LRHC, prevSegment.URHC, currentSegment.ULHC);
-
-      if (candidate1 == null && candidate2 == null && candidate3 == null && candidate4 == null) {
-        // The planes are identical.  We wouldn't need a circle at all except for the possibility of
-        // backing up, which is hard to detect here.
-        final SegmentEndpoint midEndpoint = new SegmentEndpoint(currentSegment.start, 
-          prevSegment.endCutoffPlane, currentSegment.startCutoffPlane, currentSegment.ULHC, currentSegment.LLHC);
-        //don't need a circle at all.  Special constructor...
-        endPoints.add(midEndpoint);
-      } else {
-        endPoints.add(new SegmentEndpoint(currentSegment.start,
-          prevSegment.endCutoffPlane, currentSegment.startCutoffPlane,
-          prevSegment.URHC, prevSegment.LRHC,
-          currentSegment.ULHC, currentSegment.LLHC,
-          candidate1, candidate2, candidate3, candidate4));
-      }
-    }
-    // Do final endpoint
-    final PathSegment lastSegment = segments.get(segments.size()-1);
-    endPoints.add(new SegmentEndpoint(lastSegment.end,
-      lastSegment.endCutoffPlane, lastSegment.URHC, lastSegment.LRHC));
-
-  }
-
-  @Override
-  protected double distance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    // Algorithm:
-    // (1) If the point is within any of the segments along the path, return that value.
-    // (2) If the point is within any of the segment end circles along the path, return that value.
-    double currentDistance = 0.0;
-    for (PathSegment segment : segments) {
-      double distance = segment.pathDistance(planetModel, distanceStyle, x,y,z);
-      if (distance != Double.MAX_VALUE)
-        return currentDistance + distance;
-      currentDistance += segment.fullPathDistance(distanceStyle);
-    }
-
-    int segmentIndex = 0;
-    currentDistance = 0.0;
-    for (SegmentEndpoint endpoint : endPoints) {
-      double distance = endpoint.pathDistance(distanceStyle, x, y, z);
-      if (distance != Double.MAX_VALUE)
-        return currentDistance + distance;
-      if (segmentIndex < segments.size())
-        currentDistance += segments.get(segmentIndex++).fullPathDistance(distanceStyle);
-    }
-
-    return Double.MAX_VALUE;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    double minDistance = Double.MAX_VALUE;
-    for (final SegmentEndpoint endpoint : endPoints) {
-      final double newDistance = endpoint.outsideDistance(distanceStyle, x,y,z);
-      if (newDistance < minDistance)
-        minDistance = newDistance;
-    }
-    for (final PathSegment segment : segments) {
-      final double newDistance = segment.outsideDistance(planetModel, distanceStyle, x, y, z);
-      if (newDistance < minDistance)
-        minDistance = newDistance;
-    }
-    return minDistance;
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    for (SegmentEndpoint pathPoint : endPoints) {
-      if (pathPoint.isWithin(x, y, z))
-        return true;
-    }
-    for (PathSegment pathSegment : segments) {
-      if (pathSegment.isWithin(x, y, z))
-        return true;
-    }
-    return false;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane plane, final GeoPoint[] notablePoints, final Membership... bounds) {
-    // We look for an intersection with any of the exterior edges of the path.
-    // We also have to look for intersections with the cones described by the endpoints.
-    // Return "true" if any such intersections are found.
-
-    // For plane intersections, the basic idea is to come up with an equation of the line that is
-    // the intersection (if any).  Then, find the intersections with the unit sphere (if any).  If
-    // any of the intersection points are within the bounds, then we've detected an intersection.
-    // Well, sort of.  We can detect intersections also due to overlap of segments with each other.
-    // But that's an edge case and we won't be optimizing for it.
-    //System.err.println(" Looking for intersection of plane "+plane+" with path "+this);
-    for (final SegmentEndpoint pathPoint : endPoints) {
-      if (pathPoint.intersects(planetModel, plane, notablePoints, bounds)) {
-        return true;
-      }
-    }
-
-    for (final PathSegment pathSegment : segments) {
-      if (pathSegment.intersects(planetModel, plane, notablePoints, bounds)) {
-        return true;
-      }
-    }
-
-    return false;
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    // For building bounds, order matters.  We want to traverse
-    // never more than 180 degrees longitude at a pop or we risk having the
-    // bounds object get itself inverted.  So do the edges first.
-    for (PathSegment pathSegment : segments) {
-      pathSegment.getBounds(planetModel, bounds);
-    }
-    for (SegmentEndpoint pathPoint : endPoints) {
-      pathPoint.getBounds(planetModel, bounds);
-    }
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoPath))
-      return false;
-    GeoPath p = (GeoPath) o;
-    if (!super.equals(p))
-      return false;
-    if (cutoffAngle != p.cutoffAngle)
-      return false;
-    return points.equals(p.points);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    long temp = Double.doubleToLongBits(cutoffAngle);
-    result = 31 * result + (int) (temp ^ (temp >>> 32));
-    result = 31 * result + points.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoPath: {planetmodel=" + planetModel+", width=" + cutoffAngle + "(" + cutoffAngle * 180.0 / Math.PI + "), points={" + points + "}}";
-  }
-
-  /**
-   * This is precalculated data for segment endpoint.
-   * Note well: This is not necessarily a circle.  There are four cases:
-   * (1) The path consists of a single endpoint.  In this case, we build a simple circle with the proper cutoff offset.
-   * (2) This is the end of a path.  The circle plane must be constructed to go through two supplied points and be perpendicular to a connecting plane.
-   * (2.5) Intersection, but the path on both sides is linear.  We generate a circle, but we use the cutoff planes to limit its influence in the straight line case.
-   * (3) This is an intersection in a path.  We are supplied FOUR planes.  If there are intersections within bounds for both upper and lower, then
-   *    we generate no circle at all.  If there is one intersection only, then we generate a plane that includes that intersection, as well as the remaining
-   *    cutoff plane/edge plane points.
-   */
-  public static class SegmentEndpoint {
-    /** The center point of the endpoint */
-    public final GeoPoint point;
-    /** A plane describing the circle */
-    public final SidedPlane circlePlane;
-    /** Pertinent cutoff planes from adjoining segments */
-    public final Membership[] cutoffPlanes;
-    /** Notable points for this segment endpoint */
-    public final GeoPoint[] notablePoints;
-    /** No notable points from the circle itself */
-    public final static GeoPoint[] circlePoints = new GeoPoint[0];
-    /** Null membership */
-    public final static Membership[] NO_MEMBERSHIP = new Membership[0];
-    
-    /** Base case.  Does nothing at all.
-     */
-    public SegmentEndpoint(final GeoPoint point) {
-      this.point = point;
-      this.circlePlane = null;
-      this.cutoffPlanes = null;
-      this.notablePoints = null;
-    }
-    
-    /** Constructor for case (1).
-     * Generate a simple circle cutoff plane.
-     *@param point is the center point.
-     *@param upperPoint is a point that must be on the circle plane.
-     *@param lowerPoint is another point that must be on the circle plane.
-     */
-    public SegmentEndpoint(final GeoPoint point, final Plane normalPlane, final GeoPoint upperPoint, final GeoPoint lowerPoint) {
-      this.point = point;
-      // Construct a sided plane that goes through the two points and whose normal is in the normalPlane.
-      this.circlePlane = SidedPlane.constructNormalizedPerpendicularSidedPlane(point, normalPlane, upperPoint, lowerPoint);
-      this.cutoffPlanes = NO_MEMBERSHIP;
-      this.notablePoints = circlePoints;
-    }
-    
-    /** Constructor for case (2).
-     * Generate an endpoint, given a single cutoff plane plus upper and lower edge points.
-     *@param point is the center point.
-     *@param cutoffPlane is the plane from the adjoining path segment marking the boundary between this endpoint and that segment.
-     *@param topEdgePoint is a point on the cutoffPlane that should be also on the circle plane.
-     *@param bottomEdgePoint is another point on the cutoffPlane that should be also on the circle plane.
-     */
-    public SegmentEndpoint(final GeoPoint point,
-      final SidedPlane cutoffPlane, final GeoPoint topEdgePoint, final GeoPoint bottomEdgePoint) {
-      this.point = point;
-      this.cutoffPlanes = new Membership[]{new SidedPlane(cutoffPlane)};
-      this.notablePoints = new GeoPoint[]{topEdgePoint, bottomEdgePoint};
-      // To construct the plane, we now just need D, which is simply the negative of the evaluation of the circle normal vector at one of the points.
-      this.circlePlane = SidedPlane.constructNormalizedPerpendicularSidedPlane(point, cutoffPlane, topEdgePoint, bottomEdgePoint);
-    }
-
-    /** Constructor for case (2.5).
-     * Generate an endpoint, given two cutoff planes plus upper and lower edge points.
-     *@param point is the center.
-     *@param cutoffPlane1 is one adjoining path segment cutoff plane.
-     *@param cutoffPlane2 is another adjoining path segment cutoff plane.
-     *@param topEdgePoint is a point on the cutoffPlane that should be also on the circle plane.
-     *@param bottomEdgePoint is another point on the cutoffPlane that should be also on the circle plane.
-     */
-    public SegmentEndpoint(final GeoPoint point,
-      final SidedPlane cutoffPlane1, final SidedPlane cutoffPlane2, final GeoPoint topEdgePoint, final GeoPoint bottomEdgePoint) {
-      this.point = point;
-      this.cutoffPlanes = new Membership[]{new SidedPlane(cutoffPlane1), new SidedPlane(cutoffPlane2)};
-      this.notablePoints = new GeoPoint[]{topEdgePoint, bottomEdgePoint};
-      // To construct the plane, we now just need D, which is simply the negative of the evaluation of the circle normal vector at one of the points.
-      this.circlePlane = SidedPlane.constructNormalizedPerpendicularSidedPlane(point, cutoffPlane1, topEdgePoint, bottomEdgePoint);
-    }
-    
-    /** Constructor for case (3).
-     * Generate an endpoint for an intersection, given four points.
-     *@param point is the center.
-     *@param prevCutoffPlane is the previous adjoining segment cutoff plane.
-     *@param nextCutoffPlane is the next path segment cutoff plane.
-     *@param notCand2Point is a point NOT on candidate2.
-     *@param notCand1Point is a point NOT on candidate1.
-     *@param notCand3Point is a point NOT on candidate3.
-     *@param notCand4Point is a point NOT on candidate4.
-     *@param candidate1 one of four candidate circle planes.
-     *@param candidate2 one of four candidate circle planes.
-     *@param candidate3 one of four candidate circle planes.
-     *@param candidate4 one of four candidate circle planes.
-     */
-    public SegmentEndpoint(final GeoPoint point,
-      final SidedPlane prevCutoffPlane, final SidedPlane nextCutoffPlane,
-      final GeoPoint notCand2Point, final GeoPoint notCand1Point,
-      final GeoPoint notCand3Point, final GeoPoint notCand4Point,
-      final SidedPlane candidate1, final SidedPlane candidate2, final SidedPlane candidate3, final SidedPlane candidate4) {
-      // Note: What we really need is a single plane that goes through all four points.
-      // Since that's not possible in the ellipsoid case (because three points determine a plane, not four), we
-      // need an approximation that at least creates a boundary that has no interruptions.
-      // There are three obvious choices for the third point: either (a) one of the two remaining points, or (b) the top or bottom edge
-      // intersection point.  (a) has no guarantee of continuity, while (b) is capable of producing something very far from a circle if
-      // the angle between segments is acute.
-      // The solution is to look for the side (top or bottom) that has an intersection within the shape.  We use the two points from
-      // the opposite side to determine the plane, AND we pick the third to be either of the two points on the intersecting side
-      // PROVIDED that the other point is within the final circle we come up with.
-      this.point = point;
-      
-      // We construct four separate planes, and evaluate which one includes all interior points with least overlap
-      // (Constructed beforehand because we need them for degeneracy check)
-
-      final boolean cand1IsOtherWithin = candidate1!=null?candidate1.isWithin(notCand1Point):false;
-      final boolean cand2IsOtherWithin = candidate2!=null?candidate2.isWithin(notCand2Point):false;
-      final boolean cand3IsOtherWithin = candidate3!=null?candidate3.isWithin(notCand3Point):false;
-      final boolean cand4IsOtherWithin = candidate4!=null?candidate4.isWithin(notCand4Point):false;
-      
-      if (cand1IsOtherWithin && cand2IsOtherWithin && cand3IsOtherWithin && cand4IsOtherWithin) {
-        // The only way we should see both within is if all four points are coplanar.  In that case, we default to the simplest treatment.
-        this.circlePlane = candidate1;  // doesn't matter which
-        this.notablePoints = new GeoPoint[]{notCand2Point, notCand3Point, notCand1Point, notCand4Point};
-        this.cutoffPlanes = new Membership[]{new SidedPlane(prevCutoffPlane), new SidedPlane(nextCutoffPlane)};
-      } else if (cand1IsOtherWithin) {
-        // Use candidate1, and DON'T include prevCutoffPlane in the cutoff planes list
-        this.circlePlane = candidate1;
-        this.notablePoints = new GeoPoint[]{notCand2Point, notCand3Point, notCand4Point};
-        this.cutoffPlanes = new Membership[]{new SidedPlane(nextCutoffPlane)};
-      } else if (cand2IsOtherWithin) {
-        // Use candidate2
-        this.circlePlane = candidate2;
-        this.notablePoints = new GeoPoint[]{notCand3Point, notCand4Point, notCand1Point};
-        this.cutoffPlanes = new Membership[]{new SidedPlane(nextCutoffPlane)};
-      } else if (cand3IsOtherWithin) {
-        this.circlePlane = candidate3;
-        this.notablePoints = new GeoPoint[]{notCand4Point, notCand1Point, notCand2Point};
-        this.cutoffPlanes = new Membership[]{new SidedPlane(prevCutoffPlane)};
-      } else if (cand4IsOtherWithin) {
-        this.circlePlane = candidate4;
-        this.notablePoints = new GeoPoint[]{notCand1Point, notCand2Point, notCand3Point};
-        this.cutoffPlanes = new Membership[]{new SidedPlane(prevCutoffPlane)};
-      } else {
-        // dunno what happened
-        throw new RuntimeException("Couldn't come up with a plane through three points that included the fourth");
-      }
-    }
-
-    /** Check if point is within this endpoint.
-     *@param point is the point.
-     *@return true of within.
-     */
-    public boolean isWithin(final Vector point) {
-      if (circlePlane == null)
-        return false;
-      if (!circlePlane.isWithin(point))
-        return false;
-      for (final Membership m : cutoffPlanes) {
-        if (!m.isWithin(point)) {
-          return false;
-        }
-      }
-      return true;
-    }
-
-    /** Check if point is within this endpoint.
-     *@param x is the point x.
-     *@param y is the point y.
-     *@param z is the point z.
-     *@return true of within.
-     */
-    public boolean isWithin(final double x, final double y, final double z) {
-      if (circlePlane == null)
-        return false;
-      if (!circlePlane.isWithin(x, y, z))
-        return false;
-      for (final Membership m : cutoffPlanes) {
-        if (!m.isWithin(x,y,z)) {
-          return false;
-        }
-      }
-      return true;
-    }
-
-    /** Compute interior path distance.
-     *@param distanceStyle is the distance style.
-     *@param x is the point x.
-     *@param y is the point y.
-     *@param z is the point z.
-     *@return the distance metric.
-     */
-    public double pathDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-      if (!isWithin(x,y,z))
-        return Double.MAX_VALUE;
-      return distanceStyle.computeDistance(this.point, x, y, z);
-    }
-
-    /** Compute external distance.
-     *@param distanceStyle is the distance style.
-     *@param x is the point x.
-     *@param y is the point y.
-     *@param z is the point z.
-     *@return the distance metric.
-     */
-    public double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-      return distanceStyle.computeDistance(this.point, x, y, z);
-    }
-
-    /** Determine if this endpoint intersects a specified plane.
-     *@param planetModel is the planet model.
-     *@param p is the plane.
-     *@param notablePoints are the points associated with the plane.
-     *@param bounds are any bounds which the intersection must lie within.
-     *@return true if there is a matching intersection.
-     */
-    public boolean intersects(final PlanetModel planetModel, final Plane p, final GeoPoint[] notablePoints, final Membership[] bounds) {
-      //System.err.println("  looking for intersection between plane "+p+" and circle "+circlePlane+" on proper side of "+cutoffPlanes+" within "+bounds);
-      if (circlePlane == null)
-        return false;
-      return circlePlane.intersects(planetModel, p, notablePoints, this.notablePoints, bounds, this.cutoffPlanes);
-    }
-
-    /** Get the bounds for a segment endpoint.
-     *@param planetModel is the planet model.
-     *@param bounds are the bounds to be modified.
-     */
-    public void getBounds(final PlanetModel planetModel, Bounds bounds) {
-      bounds.addPoint(point);
-      if (circlePlane == null)
-        return;
-      bounds.addPlane(planetModel, circlePlane);
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      if (!(o instanceof SegmentEndpoint))
-        return false;
-      SegmentEndpoint other = (SegmentEndpoint) o;
-      return point.equals(other.point);
-    }
-
-    @Override
-    public int hashCode() {
-      return point.hashCode();
-    }
-
-    @Override
-    public String toString() {
-      return point.toString();
-    }
-  }
-
-  /**
-   * This is the pre-calculated data for a path segment.
-   */
-  public static class PathSegment {
-    /** Starting point of the segment */
-    public final GeoPoint start;
-    /** End point of the segment */
-    public final GeoPoint end;
-    /** Place to keep any complete segment distances we've calculated so far */
-    public final Map<DistanceStyle,Double> fullDistanceCache = new HashMap<DistanceStyle,Double>();
-    /** Normalized plane connecting the two points and going through world center */
-    public final Plane normalizedConnectingPlane;
-    /** Cutoff plane parallel to connecting plane representing one side of the path segment */
-    public final SidedPlane upperConnectingPlane;
-    /** Cutoff plane parallel to connecting plane representing the other side of the path segment */
-    public final SidedPlane lowerConnectingPlane;
-    /** Plane going through the center and start point, marking the start edge of the segment */
-    public final SidedPlane startCutoffPlane;
-    /** Plane going through the center and end point, marking the end edge of the segment */
-    public final SidedPlane endCutoffPlane;
-    /** Upper right hand corner of segment */
-    public final GeoPoint URHC;
-    /** Lower right hand corner of segment */
-    public final GeoPoint LRHC;
-    /** Upper left hand corner of segment */
-    public final GeoPoint ULHC;
-    /** Lower left hand corner of segment */
-    public final GeoPoint LLHC;
-    /** Notable points for the upper connecting plane */
-    public final GeoPoint[] upperConnectingPlanePoints;
-    /** Notable points for the lower connecting plane */
-    public final GeoPoint[] lowerConnectingPlanePoints;
-    /** Notable points for the start cutoff plane */
-    public final GeoPoint[] startCutoffPlanePoints;
-    /** Notable points for the end cutoff plane */
-    public final GeoPoint[] endCutoffPlanePoints;
-
-    /** Construct a path segment.
-     *@param planetModel is the planet model.
-     *@param start is the starting point.
-     *@param end is the ending point.
-     *@param normalizedConnectingPlane is the connecting plane.
-     *@param planeBoundingOffset is the linear offset from the connecting plane to either side.
-     */
-    public PathSegment(final PlanetModel planetModel, final GeoPoint start, final GeoPoint end,
-      final Plane normalizedConnectingPlane, final double planeBoundingOffset) {
-      this.start = start;
-      this.end = end;
-      this.normalizedConnectingPlane = normalizedConnectingPlane;
-        
-      // Either start or end should be on the correct side
-      upperConnectingPlane = new SidedPlane(start, normalizedConnectingPlane, -planeBoundingOffset);
-      lowerConnectingPlane = new SidedPlane(start, normalizedConnectingPlane, planeBoundingOffset);
-      // Cutoff planes use opposite endpoints as correct side examples
-      startCutoffPlane = new SidedPlane(end, normalizedConnectingPlane, start);
-      endCutoffPlane = new SidedPlane(start, normalizedConnectingPlane, end);
-      final Membership[] upperSide = new Membership[]{upperConnectingPlane};
-      final Membership[] lowerSide = new Membership[]{lowerConnectingPlane};
-      final Membership[] startSide = new Membership[]{startCutoffPlane};
-      final Membership[] endSide = new Membership[]{endCutoffPlane};
-      GeoPoint[] points;
-      points = upperConnectingPlane.findIntersections(planetModel, startCutoffPlane, lowerSide, endSide);
-      if (points.length == 0) {
-        throw new IllegalArgumentException("Some segment boundary points are off the ellipsoid; path too wide");
-      }
-      this.ULHC = points[0];
-      points = upperConnectingPlane.findIntersections(planetModel, endCutoffPlane, lowerSide, startSide);
-      if (points.length == 0) {
-        throw new IllegalArgumentException("Some segment boundary points are off the ellipsoid; path too wide");
-      }
-      this.URHC = points[0];
-      points = lowerConnectingPlane.findIntersections(planetModel, startCutoffPlane, upperSide, endSide);
-      if (points.length == 0) {
-        throw new IllegalArgumentException("Some segment boundary points are off the ellipsoid; path too wide");
-      }
-      this.LLHC = points[0];
-      points = lowerConnectingPlane.findIntersections(planetModel, endCutoffPlane, upperSide, startSide);
-      if (points.length == 0) {
-        throw new IllegalArgumentException("Some segment boundary points are off the ellipsoid; path too wide");
-      }
-      this.LRHC = points[0];
-      upperConnectingPlanePoints = new GeoPoint[]{ULHC, URHC};
-      lowerConnectingPlanePoints = new GeoPoint[]{LLHC, LRHC};
-      startCutoffPlanePoints = new GeoPoint[]{ULHC, LLHC};
-      endCutoffPlanePoints = new GeoPoint[]{URHC, LRHC};
-    }
-
-    /** Compute the full distance along this path segment.
-     *@param distanceStyle is the distance style.
-     *@return the distance metric.
-     */
-    public double fullPathDistance(final DistanceStyle distanceStyle) {
-      synchronized (fullDistanceCache) {
-        Double dist = fullDistanceCache.get(distanceStyle);
-        if (dist == null) {
-          dist = new Double(distanceStyle.computeDistance(start, end.x, end.y, end.z));
-          fullDistanceCache.put(distanceStyle, dist);
-        }
-        return dist.doubleValue();
-      }
-    }
-  
-    /** Check if point is within this segment.
-     *@param point is the point.
-     *@return true of within.
-     */
-    public boolean isWithin(final Vector point) {
-      return startCutoffPlane.isWithin(point) &&
-          endCutoffPlane.isWithin(point) &&
-          upperConnectingPlane.isWithin(point) &&
-          lowerConnectingPlane.isWithin(point);
-    }
-
-    /** Check if point is within this segment.
-     *@param x is the point x.
-     *@param y is the point y.
-     *@param z is the point z.
-     *@return true of within.
-     */
-    public boolean isWithin(final double x, final double y, final double z) {
-      return startCutoffPlane.isWithin(x, y, z) &&
-          endCutoffPlane.isWithin(x, y, z) &&
-          upperConnectingPlane.isWithin(x, y, z) &&
-          lowerConnectingPlane.isWithin(x, y, z);
-    }
-
-    /** Compute interior path distance.
-     *@param planetModel is the planet model.
-     *@param distanceStyle is the distance style.
-     *@param x is the point x.
-     *@param y is the point y.
-     *@param z is the point z.
-     *@return the distance metric.
-     */
-    public double pathDistance(final PlanetModel planetModel, final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-      if (!isWithin(x,y,z))
-        return Double.MAX_VALUE;
-
-      // (1) Compute normalizedPerpPlane.  If degenerate, then return point distance from start to point.
-      // Want no allocations or expensive operations!  so we do this the hard way
-      final double perpX = normalizedConnectingPlane.y * z - normalizedConnectingPlane.z * y;
-      final double perpY = normalizedConnectingPlane.z * x - normalizedConnectingPlane.x * z;
-      final double perpZ = normalizedConnectingPlane.x * y - normalizedConnectingPlane.y * x;
-      final double magnitude = Math.sqrt(perpX * perpX + perpY * perpY + perpZ * perpZ);
-      if (Math.abs(magnitude) < Vector.MINIMUM_RESOLUTION)
-        return distanceStyle.computeDistance(start, x,y,z);
-      final double normFactor = 1.0/magnitude;
-      final Plane normalizedPerpPlane = new Plane(perpX * normFactor, perpY * normFactor, perpZ * normFactor, 0.0);
-      
-      // Old computation: too expensive, because it calculates the intersection point twice.
-      //return distanceStyle.computeDistance(planetModel, normalizedConnectingPlane, x, y, z, startCutoffPlane, endCutoffPlane) +
-      //  distanceStyle.computeDistance(planetModel, normalizedPerpPlane, start.x, start.y, start.z, upperConnectingPlane, lowerConnectingPlane);
-
-      final GeoPoint[] intersectionPoints = normalizedConnectingPlane.findIntersections(planetModel, normalizedPerpPlane);
-      GeoPoint thePoint;
-      if (intersectionPoints.length == 0)
-        throw new RuntimeException("Can't find world intersection for point x="+x+" y="+y+" z="+z);
-      else if (intersectionPoints.length == 1)
-        thePoint = intersectionPoints[0];
-      else {
-        if (startCutoffPlane.isWithin(intersectionPoints[0]) && endCutoffPlane.isWithin(intersectionPoints[0]))
-          thePoint = intersectionPoints[0];
-        else if (startCutoffPlane.isWithin(intersectionPoints[1]) && endCutoffPlane.isWithin(intersectionPoints[1]))
-          thePoint = intersectionPoints[1];
-        else
-          throw new RuntimeException("Can't find world intersection for point x="+x+" y="+y+" z="+z);
-      }
-      return distanceStyle.computeDistance(thePoint, x, y, z) + distanceStyle.computeDistance(start, thePoint.x, thePoint.y, thePoint.z);
-    }
-
-    /** Compute external distance.
-     *@param planetModel is the planet model.
-     *@param distanceStyle is the distance style.
-     *@param x is the point x.
-     *@param y is the point y.
-     *@param z is the point z.
-     *@return the distance metric.
-     */
-    public double outsideDistance(final PlanetModel planetModel, final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-      final double upperDistance = distanceStyle.computeDistance(planetModel, upperConnectingPlane, x,y,z, lowerConnectingPlane, startCutoffPlane, endCutoffPlane);
-      final double lowerDistance = distanceStyle.computeDistance(planetModel, lowerConnectingPlane, x,y,z, upperConnectingPlane, startCutoffPlane, endCutoffPlane);
-      final double startDistance = distanceStyle.computeDistance(planetModel, startCutoffPlane, x,y,z, endCutoffPlane, lowerConnectingPlane, upperConnectingPlane);
-      final double endDistance = distanceStyle.computeDistance(planetModel, endCutoffPlane, x,y,z, startCutoffPlane, lowerConnectingPlane, upperConnectingPlane);
-      final double ULHCDistance = distanceStyle.computeDistance(ULHC, x,y,z);
-      final double URHCDistance = distanceStyle.computeDistance(URHC, x,y,z);
-      final double LLHCDistance = distanceStyle.computeDistance(LLHC, x,y,z);
-      final double LRHCDistance = distanceStyle.computeDistance(LRHC, x,y,z);
-      return Math.min(
-        Math.min(
-          Math.min(upperDistance,lowerDistance),
-          Math.min(startDistance,endDistance)),
-        Math.min(
-          Math.min(ULHCDistance, URHCDistance),
-          Math.min(LLHCDistance, LRHCDistance)));
-    }
-
-    /** Determine if this endpoint intersects a specified plane.
-     *@param planetModel is the planet model.
-     *@param p is the plane.
-     *@param notablePoints are the points associated with the plane.
-     *@param bounds are any bounds which the intersection must lie within.
-     *@return true if there is a matching intersection.
-     */
-    public boolean intersects(final PlanetModel planetModel, final Plane p, final GeoPoint[] notablePoints, final Membership[] bounds) {
-      return upperConnectingPlane.intersects(planetModel, p, notablePoints, upperConnectingPlanePoints, bounds, lowerConnectingPlane, startCutoffPlane, endCutoffPlane) ||
-          lowerConnectingPlane.intersects(planetModel, p, notablePoints, lowerConnectingPlanePoints, bounds, upperConnectingPlane, startCutoffPlane, endCutoffPlane);
-    }
-
-    /** Get the bounds for a segment endpoint.
-     *@param planetModel is the planet model.
-     *@param bounds are the bounds to be modified.
-     */
-    public void getBounds(final PlanetModel planetModel, Bounds bounds) {
-      // We need to do all bounding planes as well as corner points
-      bounds.addPoint(start).addPoint(end).addPoint(ULHC).addPoint(URHC).addPoint(LRHC).addPoint(LLHC);
-      bounds.addPlane(planetModel, upperConnectingPlane, lowerConnectingPlane, startCutoffPlane, endCutoffPlane);
-      bounds.addPlane(planetModel, lowerConnectingPlane, upperConnectingPlane, startCutoffPlane, endCutoffPlane);
-      bounds.addPlane(planetModel, startCutoffPlane, endCutoffPlane, upperConnectingPlane, lowerConnectingPlane);
-      bounds.addPlane(planetModel, endCutoffPlane, startCutoffPlane, upperConnectingPlane, lowerConnectingPlane);
-    }
-
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPoint.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPoint.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPoint.java
deleted file mode 100755
index e8a265d..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPoint.java
+++ /dev/null
@@ -1,193 +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.geo3d;
-    
-/**
- * This class represents a point on the surface of a sphere or ellipsoid.
- *
- * @lucene.experimental
- */
-public class GeoPoint extends Vector {
-  
-  // By making lazily-evaluated variables be "volatile", we guarantee atomicity when they
-  // are updated.  This is necessary if we are using these classes in a multi-thread fashion,
-  // because we don't try to synchronize for the lazy computation.
-  
-  /** This is the lazily-evaluated magnitude.  Some constructors include it, but others don't, and
-   * we try not to create extra computation by always computing it.  Does not need to be
-   * synchronized for thread safety, because depends wholly on immutable variables of this class. */
-  protected volatile double magnitude = Double.NEGATIVE_INFINITY;
-  /** Lazily-evaluated latitude.  Does not need to be
-   * synchronized for thread safety, because depends wholly on immutable variables of this class.  */
-  protected volatile double latitude = Double.NEGATIVE_INFINITY;
-  /** Lazily-evaluated longitude.   Does not need to be
-   * synchronized for thread safety, because depends wholly on immutable variables of this class.  */
-  protected volatile double longitude = Double.NEGATIVE_INFINITY;
-
-  /** Construct a GeoPoint from the trig functions of a lat and lon pair.
-   * @param planetModel is the planetModel to put the point on.
-   * @param sinLat is the sin of the latitude.
-   * @param sinLon is the sin of the longitude.
-   * @param cosLat is the cos of the latitude.
-   * @param cosLon is the cos of the longitude.
-   * @param lat is the latitude.
-   * @param lon is the longitude.
-   */
-  public GeoPoint(final PlanetModel planetModel, final double sinLat, final double sinLon, final double cosLat, final double cosLon, final double lat, final double lon) {
-    this(computeDesiredEllipsoidMagnitude(planetModel, cosLat * cosLon, cosLat * sinLon, sinLat),
-      cosLat * cosLon, cosLat * sinLon, sinLat, lat, lon);
-  }
-  
-  /** Construct a GeoPoint from the trig functions of a lat and lon pair.
-   * @param planetModel is the planetModel to put the point on.
-   * @param sinLat is the sin of the latitude.
-   * @param sinLon is the sin of the longitude.
-   * @param cosLat is the cos of the latitude.
-   * @param cosLon is the cos of the longitude.
-   */
-  public GeoPoint(final PlanetModel planetModel, final double sinLat, final double sinLon, final double cosLat, final double cosLon) {
-    this(computeDesiredEllipsoidMagnitude(planetModel, cosLat * cosLon, cosLat * sinLon, sinLat),
-      cosLat * cosLon, cosLat * sinLon, sinLat);
-  }
-
-  /** Construct a GeoPoint from a latitude/longitude pair.
-   * @param planetModel is the planetModel to put the point on.
-   * @param lat is the latitude.
-   * @param lon is the longitude.
-   */
-  public GeoPoint(final PlanetModel planetModel, final double lat, final double lon) {
-    this(planetModel, Math.sin(lat), Math.sin(lon), Math.cos(lat), Math.cos(lon), lat, lon);
-  }
-  
-  /** Construct a GeoPoint from a unit (x,y,z) vector and a magnitude.
-   * @param magnitude is the desired magnitude, provided to put the point on the ellipsoid.
-   * @param x is the unit x value.
-   * @param y is the unit y value.
-   * @param z is the unit z value.
-   * @param lat is the latitude.
-   * @param lon is the longitude.
-   */
-  public GeoPoint(final double magnitude, final double x, final double y, final double z, double lat, double lon) {
-    super(x * magnitude, y * magnitude, z * magnitude);
-    this.magnitude = magnitude;
-    if (lat > Math.PI * 0.5 || lat < -Math.PI * 0.5) {
-      throw new IllegalArgumentException("Latitude " + lat + " is out of range: must range from -Math.PI/2 to Math.PI/2");
-    }
-    if (lon < -Math.PI || lon > Math.PI) {
-      throw new IllegalArgumentException("Longitude " + lon + " is out of range: must range from -Math.PI to Math.PI");
-    }
-    this.latitude = lat;
-    this.longitude = lon;
-  }
-
-  /** Construct a GeoPoint from a unit (x,y,z) vector and a magnitude.
-   * @param magnitude is the desired magnitude, provided to put the point on the ellipsoid.
-   * @param x is the unit x value.
-   * @param y is the unit y value.
-   * @param z is the unit z value.
-   */
-  public GeoPoint(final double magnitude, final double x, final double y, final double z) {
-    super(x * magnitude, y * magnitude, z * magnitude);
-    this.magnitude = magnitude;
-  }
-  
-  /** Construct a GeoPoint from an (x,y,z) value.
-   * The (x,y,z) tuple must be on the desired ellipsoid.
-   * @param x is the ellipsoid point x value.
-   * @param y is the ellipsoid point y value.
-   * @param z is the ellipsoid point z value.
-   */
-  public GeoPoint(final double x, final double y, final double z) {
-    super(x, y, z);
-  }
-
-  /** Compute an arc distance between two points.
-   * Note: this is an angular distance, and not a surface distance, and is therefore independent of planet model.
-   * For surface distance, see {@link org.apache.lucene.geo3d.PlanetModel#surfaceDistance(GeoPoint, GeoPoint)}
-   * @param v is the second point.
-   * @return the angle, in radians, between the two points.
-   */
-  public double arcDistance(final GeoPoint v) {
-    return Tools.safeAcos(dotProduct(v)/(magnitude() * v.magnitude()));
-  }
-
-  /** Compute an arc distance between two points.
-   * @param x is the x part of the second point.
-   * @param y is the y part of the second point.
-   * @param z is the z part of the second point.
-   * @return the angle, in radians, between the two points.
-   */
-  public double arcDistance(final double x, final double y, final double z) {
-    return Tools.safeAcos(dotProduct(x,y,z)/(magnitude() * Vector.magnitude(x,y,z)));
-  }
-
-  /** Compute the latitude for the point.
-   * @return the latitude.
-   */
-  public double getLatitude() {
-    double lat = this.latitude;//volatile-read once
-    if (lat == Double.NEGATIVE_INFINITY)
-      this.latitude = lat = Math.asin(z / magnitude());
-    return lat;
-  }
-  
-  /** Compute the longitude for the point.
-   * @return the longitude value.  Uses 0.0 if there is no computable longitude.
-   */
-  public double getLongitude() {
-    double lon = this.longitude;//volatile-read once
-    if (lon == Double.NEGATIVE_INFINITY) {
-      if (Math.abs(x) < MINIMUM_RESOLUTION && Math.abs(y) < MINIMUM_RESOLUTION)
-        this.longitude = lon = 0.0;
-      else
-        this.longitude = lon = Math.atan2(y,x);
-    }
-    return lon;
-  }
-  
-  /** Compute the linear magnitude of the point.
-   * @return the magnitude.
-   */
-  @Override
-  public double magnitude() {
-    double mag = this.magnitude;//volatile-read once
-    if (mag == Double.NEGATIVE_INFINITY) {
-      this.magnitude = mag = super.magnitude();
-    }
-    return mag;
-  }
-  
-  /** Compute whether point matches another.
-   *@param x is the x value
-   *@param y is the y value
-   *@param z is the z value
-   *@return true if the same.
-   */
-  public boolean isIdentical(final double x, final double y, final double z) {
-    return Math.abs(this.x - x) < MINIMUM_RESOLUTION &&
-      Math.abs(this.y - y) < MINIMUM_RESOLUTION &&
-      Math.abs(this.z - z) < MINIMUM_RESOLUTION;
-  }
-  
-  @Override
-  public String toString() {
-    if (this.longitude == Double.NEGATIVE_INFINITY) {
-      return super.toString();
-    }
-    return "[lat="+getLatitude()+", lon="+getLongitude()+"]";
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPolygon.java
deleted file mode 100644
index 634406d..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPolygon.java
+++ /dev/null
@@ -1,26 +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.geo3d;
-
-/**
- * GeoPolygon interface description.
- *
- * @lucene.experimental
- */
-public interface GeoPolygon extends GeoMembershipShape {
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPolygonFactory.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPolygonFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPolygonFactory.java
deleted file mode 100755
index 0dc70a5..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoPolygonFactory.java
+++ /dev/null
@@ -1,187 +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.geo3d;
-
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.List;
-
-/**
- * Class which constructs a GeoMembershipShape representing an arbitrary polygon.
- *
- * @lucene.experimental
- */
-public class GeoPolygonFactory {
-  private GeoPolygonFactory() {
-  }
-
-  /**
-   * Create a GeoMembershipShape of the right kind given the specified bounds.
-   *
-   * @param pointList        is a list of the GeoPoints to build an arbitrary polygon out of.
-   * @param convexPointIndex is the index of a single convex point whose conformation with
-   *                         its neighbors determines inside/outside for the entire polygon.
-   * @return a GeoPolygon corresponding to what was specified.
-   */
-  public static GeoPolygon makeGeoPolygon(final PlanetModel planetModel, final List<GeoPoint> pointList, final int convexPointIndex) {
-    // The basic operation uses a set of points, two points determining one particular edge, and a sided plane
-    // describing membership.
-    return buildPolygonShape(planetModel, pointList, convexPointIndex, getLegalIndex(convexPointIndex + 1, pointList.size()),
-        new SidedPlane(pointList.get(getLegalIndex(convexPointIndex - 1, pointList.size())),
-            pointList.get(convexPointIndex), pointList.get(getLegalIndex(convexPointIndex + 1, pointList.size()))),
-        false);
-  }
-
-  /** Build a GeoMembershipShape given points, starting edge, and whether starting edge is internal or not.
-   * @param pointsList        is a list of the GeoPoints to build an arbitrary polygon out of.
-   * @param startPointIndex is one of the points constituting the starting edge.
-   * @param endPointIndex is another of the points constituting the starting edge.
-   * @param startingEdge is the plane describing the starting edge.
-   * @param isInternalEdge is true if the specified edge is an internal one.
-   * @return a GeoMembershipShape corresponding to what was specified.
-   */
-  public static GeoPolygon buildPolygonShape(final PlanetModel planetModel, final List<GeoPoint> pointsList, final int startPointIndex, final int endPointIndex, final SidedPlane startingEdge, final boolean isInternalEdge) {
-    // Algorithm as follows:
-    // Start with sided edge.  Go through all points in some order.  For each new point, determine if the point is within all edges considered so far.
-    // If not, put it into a list of points for recursion.  If it is within, add new edge and keep going.
-    // Once we detect a point that is within, if there are points put aside for recursion, then call recursively.
-
-    // Current composite.  This is what we'll actually be returning.
-    final GeoCompositePolygon rval = new GeoCompositePolygon();
-
-    final List<GeoPoint> recursionList = new ArrayList<GeoPoint>();
-    final List<GeoPoint> currentList = new ArrayList<GeoPoint>();
-    final BitSet internalEdgeList = new BitSet();
-    final List<SidedPlane> currentPlanes = new ArrayList<SidedPlane>();
-
-    // Initialize the current list and current planes
-    currentList.add(pointsList.get(startPointIndex));
-    currentList.add(pointsList.get(endPointIndex));
-    internalEdgeList.set(currentPlanes.size(), isInternalEdge);
-    currentPlanes.add(startingEdge);
-
-    // Now, scan all remaining points, in order.  We'll use an index and just add to it.
-    for (int i = 0; i < pointsList.size() - 2; i++) {
-      GeoPoint newPoint = pointsList.get(getLegalIndex(i + endPointIndex + 1, pointsList.size()));
-      if (isWithin(newPoint, currentPlanes)) {
-        // Construct a sided plane based on the last two points, and the previous point
-        SidedPlane newBoundary = new SidedPlane(currentList.get(currentList.size() - 2), newPoint, currentList.get(currentList.size() - 1));
-        // Construct a sided plane based on the return trip
-        SidedPlane returnBoundary = new SidedPlane(currentList.get(currentList.size() - 1), currentList.get(0), newPoint);
-        // Verify that none of the points beyond the new point in the list are inside the polygon we'd
-        // be creating if we stopped making the current polygon right now.
-        boolean pointInside = false;
-        for (int j = i + 1; j < pointsList.size() - 2; j++) {
-          GeoPoint checkPoint = pointsList.get(getLegalIndex(j + endPointIndex + 1, pointsList.size()));
-          boolean isInside = true;
-          if (isInside && !newBoundary.isWithin(checkPoint))
-            isInside = false;
-          if (isInside && !returnBoundary.isWithin(checkPoint))
-            isInside = false;
-          if (isInside) {
-            for (SidedPlane plane : currentPlanes) {
-              if (!plane.isWithin(checkPoint)) {
-                isInside = false;
-                break;
-              }
-            }
-          }
-          if (isInside) {
-            pointInside = true;
-            break;
-          }
-        }
-        if (!pointInside) {
-          // Any excluded points?
-          boolean isInternalBoundary = recursionList.size() > 0;
-          if (isInternalBoundary) {
-            // Handle exclusion
-            recursionList.add(newPoint);
-            recursionList.add(currentList.get(currentList.size() - 1));
-            if (recursionList.size() == pointsList.size()) {
-              // We are trying to recurse with a list the same size as the one we started with.
-              // Clearly, the polygon cannot be constructed
-              throw new IllegalArgumentException("Polygon is illegal; cannot be decomposed into convex parts");
-            }
-            // We want the other side for the recursion
-            SidedPlane otherSideNewBoundary = new SidedPlane(newBoundary);
-            rval.addShape(buildPolygonShape(planetModel, recursionList, recursionList.size() - 2, recursionList.size() - 1, otherSideNewBoundary, true));
-            recursionList.clear();
-          }
-          currentList.add(newPoint);
-          internalEdgeList.set(currentPlanes.size(), isInternalBoundary);
-          currentPlanes.add(newBoundary);
-        } else {
-          recursionList.add(newPoint);
-        }
-      } else {
-        recursionList.add(newPoint);
-      }
-    }
-
-    boolean returnEdgeInternalBoundary = recursionList.size() > 0;
-    if (returnEdgeInternalBoundary) {
-      // The last step back to the start point had a recursion, so take care of that before we complete our work
-      recursionList.add(currentList.get(0));
-      recursionList.add(currentList.get(currentList.size() - 1));
-      if (recursionList.size() == pointsList.size()) {
-        // We are trying to recurse with a list the same size as the one we started with.
-        // Clearly, the polygon cannot be constructed
-        throw new IllegalArgumentException("Polygon is illegal; cannot be decomposed into convex parts");
-      }
-      // Construct a sided plane based on these two points, and the previous point
-      SidedPlane newBoundary = new SidedPlane(currentList.get(currentList.size() - 2), currentList.get(0), currentList.get(currentList.size() - 1));
-      // We want the other side for the recursion
-      SidedPlane otherSideNewBoundary = new SidedPlane(newBoundary);
-      rval.addShape(buildPolygonShape(planetModel, recursionList, recursionList.size() - 2, recursionList.size() - 1, otherSideNewBoundary, true));
-      recursionList.clear();
-    }
-    // Now, add in the current shape.
-    rval.addShape(new GeoConvexPolygon(planetModel, currentList, internalEdgeList, returnEdgeInternalBoundary));
-    //System.out.println("Done creating polygon");
-    return rval;
-  }
-
-  /** Check if a point is within a described list of planes.
-   *@param newPoint is the point. 
-   *@param currentPlanes is the list of planes.
-   *@return true if within.
-   */
-  protected static boolean isWithin(final GeoPoint newPoint, final List<SidedPlane> currentPlanes) {
-    for (SidedPlane p : currentPlanes) {
-      if (!p.isWithin(newPoint))
-        return false;
-    }
-    return true;
-  }
-
-  /** Convert raw point index into valid array position.
-   *@param index is the array index.
-   *@param size is the array size.
-   *@return an updated index.
-   */
-  protected static int getLegalIndex(int index, int size) {
-    while (index < 0) {
-      index += size;
-    }
-    while (index >= size) {
-      index -= size;
-    }
-    return index;
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoRectangle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoRectangle.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoRectangle.java
deleted file mode 100755
index fc2a531..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoRectangle.java
+++ /dev/null
@@ -1,288 +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.geo3d;
-
-/**
- * Bounding box limited on four sides (top lat, bottom lat, left lon, right lon).
- * The left-right maximum extent for this shape is PI; for anything larger, use
- * GeoWideRectangle.
- *
- * @lucene.internal
- */
-public class GeoRectangle extends GeoBaseBBox {
-  /** The top latitude of the rect */
-  protected final double topLat;
-  /** The bottom latitude of the rect */
-  protected final double bottomLat;
-  /** The left longitude of the rect */
-  protected final double leftLon;
-  /** The right longitude of the rect */
-  protected final double rightLon;
-  /** The cosine of a middle latitude */
-  protected final double cosMiddleLat;
-
-  /** The upper left hand corner point */
-  protected final GeoPoint ULHC;
-  /** The upper right hand corner point */
-  protected final GeoPoint URHC;
-  /** The lower right hand corner point */
-  protected final GeoPoint LRHC;
-  /** The lower left hand corner point */
-  protected final GeoPoint LLHC;
-
-  /** The top plane */
-  protected final SidedPlane topPlane;
-  /** The bottom plane */
-  protected final SidedPlane bottomPlane;
-  /** The left plane */
-  protected final SidedPlane leftPlane;
-  /** The right plane */
-  protected final SidedPlane rightPlane;
-
-  /** Notable points for the top plane */
-  protected final GeoPoint[] topPlanePoints;
-  /** Notable points for the bottom plane */
-  protected final GeoPoint[] bottomPlanePoints;
-  /** Notable points for the left plane */
-  protected final GeoPoint[] leftPlanePoints;
-  /** Notable points for the right plane */
-  protected final GeoPoint[] rightPlanePoints;
-
-  /** Center point */
-  protected final GeoPoint centerPoint;
-
-  /** Edge point for this rectangle */
-  protected final GeoPoint[] edgePoints;
-
-  /**
-   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
-   *@param planetModel is the planet model.
-   *@param topLat is the top latitude.
-   *@param bottomLat is the bottom latitude.
-   *@param leftLon is the left longitude.
-   *@param rightLon is the right longitude.
-   */
-  public GeoRectangle(final PlanetModel planetModel, final double topLat, final double bottomLat, final double leftLon, double rightLon) {
-    super(planetModel);
-    // Argument checking
-    if (topLat > Math.PI * 0.5 || topLat < -Math.PI * 0.5)
-      throw new IllegalArgumentException("Top latitude out of range");
-    if (bottomLat > Math.PI * 0.5 || bottomLat < -Math.PI * 0.5)
-      throw new IllegalArgumentException("Bottom latitude out of range");
-    if (topLat < bottomLat)
-      throw new IllegalArgumentException("Top latitude less than bottom latitude");
-    if (leftLon < -Math.PI || leftLon > Math.PI)
-      throw new IllegalArgumentException("Left longitude out of range");
-    if (rightLon < -Math.PI || rightLon > Math.PI)
-      throw new IllegalArgumentException("Right longitude out of range");
-    double extent = rightLon - leftLon;
-    if (extent < 0.0) {
-      extent += 2.0 * Math.PI;
-    }
-    if (extent > Math.PI)
-      throw new IllegalArgumentException("Width of rectangle too great");
-
-    this.topLat = topLat;
-    this.bottomLat = bottomLat;
-    this.leftLon = leftLon;
-    this.rightLon = rightLon;
-
-    final double sinTopLat = Math.sin(topLat);
-    final double cosTopLat = Math.cos(topLat);
-    final double sinBottomLat = Math.sin(bottomLat);
-    final double cosBottomLat = Math.cos(bottomLat);
-    final double sinLeftLon = Math.sin(leftLon);
-    final double cosLeftLon = Math.cos(leftLon);
-    final double sinRightLon = Math.sin(rightLon);
-    final double cosRightLon = Math.cos(rightLon);
-
-    // Now build the four points
-    this.ULHC = new GeoPoint(planetModel, sinTopLat, sinLeftLon, cosTopLat, cosLeftLon, topLat, leftLon);
-    this.URHC = new GeoPoint(planetModel, sinTopLat, sinRightLon, cosTopLat, cosRightLon, topLat, rightLon);
-    this.LRHC = new GeoPoint(planetModel, sinBottomLat, sinRightLon, cosBottomLat, cosRightLon, bottomLat, rightLon);
-    this.LLHC = new GeoPoint(planetModel, sinBottomLat, sinLeftLon, cosBottomLat, cosLeftLon, bottomLat, leftLon);
-
-    final double middleLat = (topLat + bottomLat) * 0.5;
-    final double sinMiddleLat = Math.sin(middleLat);
-    this.cosMiddleLat = Math.cos(middleLat);
-    // Normalize
-    while (leftLon > rightLon) {
-      rightLon += Math.PI * 2.0;
-    }
-    final double middleLon = (leftLon + rightLon) * 0.5;
-    final double sinMiddleLon = Math.sin(middleLon);
-    final double cosMiddleLon = Math.cos(middleLon);
-
-    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinMiddleLon, cosMiddleLat, cosMiddleLon);
-
-    this.topPlane = new SidedPlane(centerPoint, planetModel, sinTopLat);
-    this.bottomPlane = new SidedPlane(centerPoint, planetModel, sinBottomLat);
-    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
-    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
-
-    this.topPlanePoints = new GeoPoint[]{ULHC, URHC};
-    this.bottomPlanePoints = new GeoPoint[]{LLHC, LRHC};
-    this.leftPlanePoints = new GeoPoint[]{ULHC, LLHC};
-    this.rightPlanePoints = new GeoPoint[]{URHC, LRHC};
-
-    this.edgePoints = new GeoPoint[]{ULHC};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    final double newTopLat = topLat + angle;
-    final double newBottomLat = bottomLat - angle;
-    // Figuring out when we escalate to a special case requires some prefiguring
-    double currentLonSpan = rightLon - leftLon;
-    if (currentLonSpan < 0.0)
-      currentLonSpan += Math.PI * 2.0;
-    double newLeftLon = leftLon - angle;
-    double newRightLon = rightLon + angle;
-    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
-      newLeftLon = -Math.PI;
-      newRightLon = Math.PI;
-    }
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return topPlane.isWithin(x, y, z) &&
-        bottomPlane.isWithin(x, y, z) &&
-        leftPlane.isWithin(x, y, z) &&
-        rightPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public double getRadius() {
-    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
-    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
-    // the distance to the right or left edge from the center.
-    final double centerAngle = (rightLon - (rightLon + leftLon) * 0.5) * cosMiddleLat;
-    final double topAngle = centerPoint.arcDistance(URHC);
-    final double bottomAngle = centerPoint.arcDistance(LLHC);
-    return Math.max(centerAngle, Math.max(topAngle, bottomAngle));
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    return centerPoint;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    return p.intersects(planetModel, topPlane, notablePoints, topPlanePoints, bounds, bottomPlane, leftPlane, rightPlane) ||
-        p.intersects(planetModel, bottomPlane, notablePoints, bottomPlanePoints, bounds, topPlane, leftPlane, rightPlane) ||
-        p.intersects(planetModel, leftPlane, notablePoints, leftPlanePoints, bounds, rightPlane, topPlane, bottomPlane) ||
-        p.intersects(planetModel, rightPlane, notablePoints, rightPlanePoints, bounds, leftPlane, topPlane, bottomPlane);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds.addHorizontalPlane(planetModel, topLat, topPlane, bottomPlane, leftPlane, rightPlane)
-      .addVerticalPlane(planetModel, rightLon, rightPlane, topPlane, bottomPlane, leftPlane)
-      .addHorizontalPlane(planetModel, bottomLat, bottomPlane, topPlane, leftPlane, rightPlane)
-      .addVerticalPlane(planetModel, leftLon, leftPlane, topPlane, bottomPlane, rightPlane)
-      .addPoint(ULHC).addPoint(URHC).addPoint(LLHC).addPoint(LRHC);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    //System.err.println(this+" getrelationship with "+path);
-    final int insideRectangle = isShapeInsideBBox(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some inside");
-      return OVERLAPS;
-    }
-
-    final boolean insideShape = path.isWithin(ULHC);
-
-    if (insideRectangle == ALL_INSIDE && insideShape) {
-      //System.err.println(" inside of each other");
-      return OVERLAPS;
-    }
-
-    if (path.intersects(topPlane, topPlanePoints, bottomPlane, leftPlane, rightPlane) ||
-        path.intersects(bottomPlane, bottomPlanePoints, topPlane, leftPlane, rightPlane) ||
-        path.intersects(leftPlane, leftPlanePoints, topPlane, bottomPlane, rightPlane) ||
-        path.intersects(rightPlane, rightPlanePoints, leftPlane, topPlane, bottomPlane)) {
-      //System.err.println(" edges intersect");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      //System.err.println(" shape inside rectangle");
-      return WITHIN;
-    }
-
-    if (insideShape) {
-      //System.err.println(" shape contains rectangle");
-      return CONTAINS;
-    }
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    final double topDistance = distanceStyle.computeDistance(planetModel, topPlane, x,y,z, bottomPlane, leftPlane, rightPlane);
-    final double bottomDistance = distanceStyle.computeDistance(planetModel, bottomPlane, x,y,z, topPlane, leftPlane, rightPlane);
-    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, rightPlane, topPlane, bottomPlane);
-    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, leftPlane, topPlane, bottomPlane);
-    
-    final double ULHCDistance = distanceStyle.computeDistance(ULHC, x,y,z);
-    final double URHCDistance = distanceStyle.computeDistance(URHC, x,y,z);
-    final double LRHCDistance = distanceStyle.computeDistance(LRHC, x,y,z);
-    final double LLHCDistance = distanceStyle.computeDistance(LLHC, x,y,z);
-    
-    return Math.min(
-      Math.min(
-        Math.min(topDistance, bottomDistance),
-        Math.min(leftDistance, rightDistance)),
-      Math.min(
-        Math.min(ULHCDistance, URHCDistance),
-        Math.min(LRHCDistance, LLHCDistance)));
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoRectangle))
-      return false;
-    GeoRectangle other = (GeoRectangle) o;
-    return super.equals(other) && other.ULHC.equals(ULHC) && other.LRHC.equals(LRHC);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result  + ULHC.hashCode();
-    result = 31 * result  + LRHC.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoRectangle: {planetmodel="+planetModel+", toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + "), bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
-  }
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoShape.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoShape.java
deleted file mode 100755
index 21cdba3..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoShape.java
+++ /dev/null
@@ -1,63 +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.geo3d;
-
-/**
- * Generic shape.  This describes methods that help GeoAreas figure out
- * how they interact with a shape, for the purposes of coming up with a
- * set of geo hash values.
- *
- * @lucene.experimental
- */
-public interface GeoShape extends Membership {
-
-  /**
-   * Return a sample point that is on the outside edge/boundary of the shape.
-   *
-   * @return samples of all edge points from distinct edge sections.  Typically one point
-   * is returned, but zero or two are also possible.
-   */
-  public GeoPoint[] getEdgePoints();
-
-  /**
-   * Assess whether a plane, within the provided bounds, intersects
-   * with the shape.  Note well that this method is allowed to return "true"
-   * if there are internal edges of a composite shape which intersect the plane.
-   * Doing this can cause getRelationship() for most GeoBBox shapes to return
-   * OVERLAPS rather than the more correct CONTAINS, but that cannot be
-   * helped for some complex shapes that are built out of overlapping parts.
-   *
-   * @param plane         is the plane to assess for intersection with the shape's edges or
-   *                      bounding curves.
-   * @param notablePoints represents the intersections of the plane with the supplied
-   *                      bounds.  These are used to disambiguate when two planes are identical and it needs
-   *                      to be determined whether any points exist that fulfill all the bounds.
-   * @param bounds        are a set of bounds that define an area that an
-   *                      intersection must be within in order to qualify (provided by a GeoArea).
-   * @return true if there's such an intersection, false if not.
-   */
-  public boolean intersects(final Plane plane, final GeoPoint[] notablePoints, final Membership... bounds);
-
-  /**
-   * Compute bounds for the shape.
-   *
-   * @param bounds is the input bounds object.
-   *             The input object will be modified.
-   */
-  public void getBounds(final Bounds bounds);
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoSizeable.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoSizeable.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoSizeable.java
deleted file mode 100755
index e8c0ebb..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoSizeable.java
+++ /dev/null
@@ -1,40 +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.geo3d;
-
-/**
- * Some shapes can compute radii of a geocircle in which they are inscribed.
- *
- * @lucene.experimental
- */
-public interface GeoSizeable {
-  /**
-   * Returns the radius of a circle into which the GeoSizeable area can
-   * be inscribed.
-   *
-   * @return the radius.
-   */
-  public double getRadius();
-
-  /**
-   * Returns the center of a circle into which the area will be inscribed.
-   *
-   * @return the center.
-   */
-  public GeoPoint getCenter();
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoSouthLatitudeZone.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoSouthLatitudeZone.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoSouthLatitudeZone.java
deleted file mode 100644
index 439dc1b..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoSouthLatitudeZone.java
+++ /dev/null
@@ -1,168 +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.geo3d;
-
-/**
- * This GeoBBox represents an area rectangle limited only in north latitude.
- *
- * @lucene.internal
- */
-public class GeoSouthLatitudeZone extends GeoBaseBBox {
-  /** The top latitude of the zone */
-  protected final double topLat;
-  /** The cosine of the top latitude of the zone */
-  protected final double cosTopLat;
-  /** The top plane of the zone */
-  protected final SidedPlane topPlane;
-  /** An interior point of the zone */
-  protected final GeoPoint interiorPoint;
-  /** Notable points for the plane (none) */
-  protected final static GeoPoint[] planePoints = new GeoPoint[0];
-  /** A point on the top boundary */
-  protected final GeoPoint topBoundaryPoint;
-  /** Edge points; a reference to the topBoundaryPoint */
-  protected final GeoPoint[] edgePoints;
-
-  /** Constructor.
-   *@param planetModel is the planet model.
-   *@param topLat is the top latitude of the zone.
-   */
-  public GeoSouthLatitudeZone(final PlanetModel planetModel, final double topLat) {
-    super(planetModel);
-    this.topLat = topLat;
-
-    final double sinTopLat = Math.sin(topLat);
-    this.cosTopLat = Math.cos(topLat);
-
-    // Compute an interior point.  Pick one whose lat is between top and bottom.
-    final double middleLat = (topLat - Math.PI * 0.5) * 0.5;
-    final double sinMiddleLat = Math.sin(middleLat);
-    this.interiorPoint = new GeoPoint(planetModel, sinMiddleLat, 0.0, Math.sqrt(1.0 - sinMiddleLat * sinMiddleLat), 1.0);
-    this.topBoundaryPoint = new GeoPoint(planetModel, sinTopLat, 0.0, Math.sqrt(1.0 - sinTopLat * sinTopLat), 1.0);
-
-    this.topPlane = new SidedPlane(interiorPoint, planetModel, sinTopLat);
-
-    this.edgePoints = new GeoPoint[]{topBoundaryPoint};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    final double newTopLat = topLat + angle;
-    final double newBottomLat = -Math.PI * 0.5;
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, -Math.PI, Math.PI);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return topPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public double getRadius() {
-    // This is a bit tricky.  I guess we should interpret this as meaning the angle of a circle that
-    // would contain all the bounding box points, when starting in the "center".
-    if (topLat > 0.0)
-      return Math.PI;
-    double maxCosLat = cosTopLat;
-    return maxCosLat * Math.PI;
-  }
-
-  /**
-   * Returns the center of a circle into which the area will be inscribed.
-   *
-   * @return the center.
-   */
-  @Override
-  public GeoPoint getCenter() {
-    return interiorPoint;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    return p.intersects(planetModel, topPlane, notablePoints, planePoints, bounds);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds
-      .addHorizontalPlane(planetModel, topLat, topPlane);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    final int insideRectangle = isShapeInsideBBox(path);
-    if (insideRectangle == SOME_INSIDE)
-      return OVERLAPS;
-
-    final boolean insideShape = path.isWithin(topBoundaryPoint);
-
-    if (insideRectangle == ALL_INSIDE && insideShape)
-      return OVERLAPS;
-
-    // Second, the shortcut of seeing whether endpoints are in/out is not going to
-    // work with no area endpoints.  So we rely entirely on intersections.
-
-    if (path.intersects(topPlane, planePoints))
-      return OVERLAPS;
-
-    // There is another case for latitude zones only.  This is when the boundaries of the shape all fit
-    // within the zone, but the shape includes areas outside the zone crossing a pole.
-    // In this case, the above "overlaps" check is insufficient.  We also need to check a point on either boundary
-    // whether it is within the shape.  If both such points are within, then CONTAINS is the right answer.  If
-    // one such point is within, then OVERLAPS is the right answer.
-
-    if (insideShape)
-      return CONTAINS;
-
-    if (insideRectangle == ALL_INSIDE)
-      return WITHIN;
-
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    return distanceStyle.computeDistance(planetModel, topPlane, x,y,z);
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoSouthLatitudeZone))
-      return false;
-    GeoSouthLatitudeZone other = (GeoSouthLatitudeZone) o;
-    return super.equals(other) && other.topBoundaryPoint.equals(topBoundaryPoint);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + topBoundaryPoint.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoSouthLatitudeZone: {planetmodel="+planetModel+", toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + ")}";
-  }
-}
-


[21/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 3a31a8c)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java
new file mode 100755
index 0000000..1f2c054
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java
@@ -0,0 +1,1657 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * We know about three kinds of planes.  First kind: general plain through two points and origin
+ * Second kind: horizontal plane at specified height.  Third kind: vertical plane with specified x and y value, through origin.
+ *
+ * @lucene.experimental
+ */
+public class Plane extends Vector {
+  /** An array with no points in it */
+  protected final static GeoPoint[] NO_POINTS = new GeoPoint[0];
+  /** An array with no bounds in it */
+  protected final static Membership[] NO_BOUNDS = new Membership[0];
+  /** A vertical plane normal to the Y axis */
+  protected final static Plane normalYPlane = new Plane(0.0,1.0,0.0,0.0);
+  /** A vertical plane normal to the X axis */
+  protected final static Plane normalXPlane = new Plane(1.0,0.0,0.0,0.0);
+  /** A vertical plane normal to the Z axis */
+  protected final static Plane normalZPlane = new Plane(0.0,0.0,1.0,0.0);
+
+  /** Ax + By + Cz + D = 0 */
+  public final double D;
+
+  /**
+   * Construct a plane with all four coefficients defined.
+   *@param A is A
+   *@param B is B
+   *@param C is C
+   *@param D is D
+   */
+  public Plane(final double A, final double B, final double C, final double D) {
+    super(A, B, C);
+    this.D = D;
+  }
+
+  /**
+   * Construct a plane through two points and origin.
+   *
+   * @param A is the first point (origin based).
+   * @param B is the second point (origin based).
+   */
+  public Plane(final Vector A, final Vector B) {
+    super(A, B);
+    D = 0.0;
+  }
+
+  /**
+   * Construct a horizontal plane at a specified Z.
+   *
+   * @param planetModel is the planet model.
+   * @param sinLat is the sin(latitude).
+   */
+  public Plane(final PlanetModel planetModel, final double sinLat) {
+    super(0.0, 0.0, 1.0);
+    D = -sinLat * computeDesiredEllipsoidMagnitude(planetModel, sinLat);
+  }
+
+  /**
+   * Construct a vertical plane through a specified
+   * x, y and origin.
+   *
+   * @param x is the specified x value.
+   * @param y is the specified y value.
+   */
+  public Plane(final double x, final double y) {
+    super(y, -x, 0.0);
+    D = 0.0;
+  }
+
+  /**
+   * Construct a plane with a specific vector, and D offset
+   * from origin.
+   * @param v is the normal vector.
+   * @param D is the D offset from the origin.
+   */
+  public Plane(final Vector v, final double D) {
+    super(v.x, v.y, v.z);
+    this.D = D;
+  }
+
+  /** Construct the most accurate normalized plane through an x-y point and including the Z axis.
+   * If none of the points can determine the plane, return null.
+   * @param planePoints is a set of points to choose from.  The best one for constructing the most precise plane is picked.
+   * @return the plane
+   */
+  public static Plane constructNormalizedZPlane(final Vector... planePoints) {
+    // Pick the best one (with the greatest x-y distance)
+    double bestDistance = 0.0;
+    Vector bestPoint = null;
+    for (final Vector point : planePoints) {
+      final double pointDist = point.x * point.x + point.y * point.y;
+      if (pointDist > bestDistance) {
+        bestDistance = pointDist;
+        bestPoint = point;
+      }
+    }
+    return constructNormalizedZPlane(bestPoint.x, bestPoint.y);
+  }
+
+  /** Construct the most accurate normalized plane through an x-z point and including the Y axis.
+   * If none of the points can determine the plane, return null.
+   * @param planePoints is a set of points to choose from.  The best one for constructing the most precise plane is picked.
+   * @return the plane
+   */
+  public static Plane constructNormalizedYPlane(final Vector... planePoints) {
+    // Pick the best one (with the greatest x-z distance)
+    double bestDistance = 0.0;
+    Vector bestPoint = null;
+    for (final Vector point : planePoints) {
+      final double pointDist = point.x * point.x + point.z * point.z;
+      if (pointDist > bestDistance) {
+        bestDistance = pointDist;
+        bestPoint = point;
+      }
+    }
+    return constructNormalizedYPlane(bestPoint.x, bestPoint.z, 0.0);
+  }
+
+  /** Construct the most accurate normalized plane through an y-z point and including the X axis.
+   * If none of the points can determine the plane, return null.
+   * @param planePoints is a set of points to choose from.  The best one for constructing the most precise plane is picked.
+   * @return the plane
+   */
+  public static Plane constructNormalizedXPlane(final Vector... planePoints) {
+    // Pick the best one (with the greatest y-z distance)
+    double bestDistance = 0.0;
+    Vector bestPoint = null;
+    for (final Vector point : planePoints) {
+      final double pointDist = point.y * point.y + point.z * point.z;
+      if (pointDist > bestDistance) {
+        bestDistance = pointDist;
+        bestPoint = point;
+      }
+    }
+    return constructNormalizedXPlane(bestPoint.y, bestPoint.z, 0.0);
+  }
+
+  /** Construct a normalized plane through an x-y point and including the Z axis.
+   * If the x-y point is at (0,0), return null.
+   * @param x is the x value.
+   * @param y is the y value.
+   * @return a plane passing through the Z axis and (x,y,0).
+   */
+  public static Plane constructNormalizedZPlane(final double x, final double y) {
+    if (Math.abs(x) < MINIMUM_RESOLUTION && Math.abs(y) < MINIMUM_RESOLUTION)
+      return null;
+    final double denom = 1.0 / Math.sqrt(x*x + y*y);
+    return new Plane(y * denom, -x * denom, 0.0, 0.0);
+  }
+
+  /** Construct a normalized plane through an x-z point and parallel to the Y axis.
+   * If the x-z point is at (0,0), return null.
+   * @param x is the x value.
+   * @param z is the z value.
+   * @param DValue is the offset from the origin for the plane.
+   * @return a plane parallel to the Y axis and perpendicular to the x and z values given.
+   */
+  public static Plane constructNormalizedYPlane(final double x, final double z, final double DValue) {
+    if (Math.abs(x) < MINIMUM_RESOLUTION && Math.abs(z) < MINIMUM_RESOLUTION)
+      return null;
+    final double denom = 1.0 / Math.sqrt(x*x + z*z);
+    return new Plane(z * denom, 0.0, -x * denom, DValue);
+  }
+
+  /** Construct a normalized plane through a y-z point and parallel to the X axis.
+   * If the y-z point is at (0,0), return null.
+   * @param y is the y value.
+   * @param z is the z value.
+   * @param DValue is the offset from the origin for the plane.
+   * @return a plane parallel to the X axis and perpendicular to the y and z values given.
+   */
+  public static Plane constructNormalizedXPlane(final double y, final double z, final double DValue) {
+    if (Math.abs(y) < MINIMUM_RESOLUTION && Math.abs(z) < MINIMUM_RESOLUTION)
+      return null;
+    final double denom = 1.0 / Math.sqrt(y*y + z*z);
+    return new Plane(0.0, z * denom, -y * denom, DValue);
+  }
+  
+  /**
+   * Evaluate the plane equation for a given point, as represented
+   * by a vector.
+   *
+   * @param v is the vector.
+   * @return the result of the evaluation.
+   */
+  public double evaluate(final Vector v) {
+    return dotProduct(v) + D;
+  }
+
+  /**
+   * Evaluate the plane equation for a given point, as represented
+   * by a vector.
+   * @param x is the x value.
+   * @param y is the y value.
+   * @param z is the z value.
+   * @return the result of the evaluation.
+   */
+  public double evaluate(final double x, final double y, final double z) {
+    return dotProduct(x, y, z) + D;
+  }
+
+  /**
+   * Evaluate the plane equation for a given point, as represented
+   * by a vector.
+   *
+   * @param v is the vector.
+   * @return true if the result is on the plane.
+   */
+  public boolean evaluateIsZero(final Vector v) {
+    return Math.abs(evaluate(v)) < MINIMUM_RESOLUTION;
+  }
+
+  /**
+   * Evaluate the plane equation for a given point, as represented
+   * by a vector.
+   *
+   * @param x is the x value.
+   * @param y is the y value.
+   * @param z is the z value.
+   * @return true if the result is on the plane.
+   */
+  public boolean evaluateIsZero(final double x, final double y, final double z) {
+    return Math.abs(evaluate(x, y, z)) < MINIMUM_RESOLUTION;
+  }
+
+  /**
+   * Build a normalized plane, so that the vector is normalized.
+   *
+   * @return the normalized plane object, or null if the plane is indeterminate.
+   */
+  public Plane normalize() {
+    Vector normVect = super.normalize();
+    if (normVect == null)
+      return null;
+    return new Plane(normVect, this.D);
+  }
+
+  /** Compute arc distance from plane to a vector expressed with a {@link GeoPoint}.
+   *  @see #arcDistance(PlanetModel, double, double, double, Membership...) */
+  public double arcDistance(final PlanetModel planetModel, final GeoPoint v, final Membership... bounds) {
+    return arcDistance(planetModel, v.x, v.y, v.z, bounds);
+  }
+    
+  /**
+   * Compute arc distance from plane to a vector.
+   * @param planetModel is the planet model.
+   * @param x is the x vector value.
+   * @param y is the y vector value.
+   * @param z is the z vector value.
+   * @param bounds are the bounds which constrain the intersection point.
+   * @return the arc distance.
+   */
+  public double arcDistance(final PlanetModel planetModel, final double x, final double y, final double z, final Membership... bounds) {
+
+    if (evaluateIsZero(x,y,z)) {
+      if (meetsAllBounds(x,y,z, bounds))
+        return 0.0;
+      return Double.MAX_VALUE;
+    }
+    
+    // First, compute the perpendicular plane.
+    final Plane perpPlane = new Plane(this.y * z - this.z * y, this.z * x - this.x * z, this.x * y - this.y * x, 0.0);
+
+    // We need to compute the intersection of two planes on the geo surface: this one, and its perpendicular.
+    // Then, we need to choose which of the two points we want to compute the distance to.  We pick the
+    // shorter distance always.
+    
+    final GeoPoint[] intersectionPoints = findIntersections(planetModel, perpPlane);
+    
+    // For each point, compute a linear distance, and take the minimum of them
+    double minDistance = Double.MAX_VALUE;
+    
+    for (final GeoPoint intersectionPoint : intersectionPoints) {
+      if (meetsAllBounds(intersectionPoint, bounds)) {
+        final double theDistance = intersectionPoint.arcDistance(x,y,z);
+        if (theDistance < minDistance) {
+          minDistance = theDistance;
+        }
+      }
+    }
+    return minDistance;
+
+  }
+
+  /**
+   * Compute normal distance from plane to a vector.
+   * @param v is the vector.
+   * @param bounds are the bounds which constrain the intersection point.
+   * @return the normal distance.
+   */
+  public double normalDistance(final Vector v, final Membership... bounds) {
+    return normalDistance(v.x, v.y, v.z, bounds);
+  }
+    
+  /**
+   * Compute normal distance from plane to a vector.
+   * @param x is the vector x.
+   * @param y is the vector y.
+   * @param z is the vector z.
+   * @param bounds are the bounds which constrain the intersection point.
+   * @return the normal distance.
+   */
+  public double normalDistance(final double x, final double y, final double z, final Membership... bounds) {
+
+    final double dist = evaluate(x,y,z);
+    final double perpX = x - dist * this.x;
+    final double perpY = y - dist * this.y;
+    final double perpZ = z - dist * this.z;
+
+    if (!meetsAllBounds(perpX, perpY, perpZ, bounds)) {
+      return Double.MAX_VALUE;
+    }
+    
+    return Math.abs(dist);
+  }
+  
+  /**
+   * Compute normal distance squared from plane to a vector.
+   * @param v is the vector.
+   * @param bounds are the bounds which constrain the intersection point.
+   * @return the normal distance squared.
+   */
+  public double normalDistanceSquared(final Vector v, final Membership... bounds) {
+    return normalDistanceSquared(v.x, v.y, v.z, bounds);
+  }
+  
+  /**
+   * Compute normal distance squared from plane to a vector.
+   * @param x is the vector x.
+   * @param y is the vector y.
+   * @param z is the vector z.
+   * @param bounds are the bounds which constrain the intersection point.
+   * @return the normal distance squared.
+   */
+  public double normalDistanceSquared(final double x, final double y, final double z, final Membership... bounds) {
+    final double normal = normalDistance(x,y,z,bounds);
+    if (normal == Double.MAX_VALUE)
+      return normal;
+    return normal * normal;
+  }
+
+  /**
+   * Compute linear distance from plane to a vector.  This is defined
+   * as the distance from the given point to the nearest intersection of 
+   * this plane with the planet surface.
+   * @param planetModel is the planet model.
+   * @param v is the point.
+   * @param bounds are the bounds which constrain the intersection point.
+   * @return the linear distance.
+   */
+  public double linearDistance(final PlanetModel planetModel, final GeoPoint v, final Membership... bounds) {
+    return linearDistance(planetModel, v.x, v.y, v.z, bounds);
+  }
+    
+  /**
+   * Compute linear distance from plane to a vector.  This is defined
+   * as the distance from the given point to the nearest intersection of 
+   * this plane with the planet surface.
+   * @param planetModel is the planet model.
+   * @param x is the vector x.
+   * @param y is the vector y.
+   * @param z is the vector z.
+   * @param bounds are the bounds which constrain the intersection point.
+   * @return the linear distance.
+   */
+  public double linearDistance(final PlanetModel planetModel, final double x, final double y, final double z, final Membership... bounds) {
+    if (evaluateIsZero(x,y,z)) {
+      if (meetsAllBounds(x,y,z, bounds))
+        return 0.0;
+      return Double.MAX_VALUE;
+    }
+    
+    // First, compute the perpendicular plane.
+    final Plane perpPlane = new Plane(this.y * z - this.z * y, this.z * x - this.x * z, this.x * y - this.y * x, 0.0);
+
+    // We need to compute the intersection of two planes on the geo surface: this one, and its perpendicular.
+    // Then, we need to choose which of the two points we want to compute the distance to.  We pick the
+    // shorter distance always.
+    
+    final GeoPoint[] intersectionPoints = findIntersections(planetModel, perpPlane);
+    
+    // For each point, compute a linear distance, and take the minimum of them
+    double minDistance = Double.MAX_VALUE;
+    
+    for (final GeoPoint intersectionPoint : intersectionPoints) {
+      if (meetsAllBounds(intersectionPoint, bounds)) {
+        final double theDistance = intersectionPoint.linearDistance(x,y,z);
+        if (theDistance < minDistance) {
+          minDistance = theDistance;
+        }
+      }
+    }
+    return minDistance;
+  }
+      
+  /**
+   * Compute linear distance squared from plane to a vector.  This is defined
+   * as the distance from the given point to the nearest intersection of 
+   * this plane with the planet surface.
+   * @param planetModel is the planet model.
+   * @param v is the point.
+   * @param bounds are the bounds which constrain the intersection point.
+   * @return the linear distance squared.
+   */
+  public double linearDistanceSquared(final PlanetModel planetModel, final GeoPoint v, final Membership... bounds) {
+    return linearDistanceSquared(planetModel, v.x, v.y, v.z, bounds);
+  }
+  
+  /**
+   * Compute linear distance squared from plane to a vector.  This is defined
+   * as the distance from the given point to the nearest intersection of 
+   * this plane with the planet surface.
+   * @param planetModel is the planet model.
+   * @param x is the vector x.
+   * @param y is the vector y.
+   * @param z is the vector z.
+   * @param bounds are the bounds which constrain the intersection point.
+   * @return the linear distance squared.
+   */
+  public double linearDistanceSquared(final PlanetModel planetModel, final double x, final double y, final double z, final Membership... bounds) {
+    final double linearDistance = linearDistance(planetModel, x, y, z, bounds);
+    return linearDistance * linearDistance;
+  }
+
+  /**
+   * Find points on the boundary of the intersection of a plane and the unit sphere,
+   * given a starting point, and ending point, and a list of proportions of the arc (e.g. 0.25, 0.5, 0.75).
+   * The angle between the starting point and ending point is assumed to be less than pi.
+   * @param start is the start point.
+   * @param end is the end point.
+   * @param proportions is an array of fractional proportions measured between start and end.
+   * @return an array of points corresponding to the proportions passed in.
+   */
+  public GeoPoint[] interpolate(final GeoPoint start, final GeoPoint end, final double[] proportions) {
+    // Steps:
+    // (1) Translate (x0,y0,z0) of endpoints into origin-centered place:
+    // x1 = x0 + D*A
+    // y1 = y0 + D*B
+    // z1 = z0 + D*C
+    // (2) Rotate counterclockwise in x-y:
+    // ra = -atan2(B,A)
+    // x2 = x1 cos ra - y1 sin ra
+    // y2 = x1 sin ra + y1 cos ra
+    // z2 = z1
+    // Faster:
+    // cos ra = A/sqrt(A^2+B^2+C^2)
+    // sin ra = -B/sqrt(A^2+B^2+C^2)
+    // cos (-ra) = A/sqrt(A^2+B^2+C^2)
+    // sin (-ra) = B/sqrt(A^2+B^2+C^2)
+    // (3) Rotate clockwise in x-z:
+    // ha = pi/2 - asin(C/sqrt(A^2+B^2+C^2))
+    // x3 = x2 cos ha - z2 sin ha
+    // y3 = y2
+    // z3 = x2 sin ha + z2 cos ha
+    // At this point, z3 should be zero.
+    // Faster:
+    // sin(ha) = cos(asin(C/sqrt(A^2+B^2+C^2))) = sqrt(1 - C^2/(A^2+B^2+C^2)) = sqrt(A^2+B^2)/sqrt(A^2+B^2+C^2)
+    // cos(ha) = sin(asin(C/sqrt(A^2+B^2+C^2))) = C/sqrt(A^2+B^2+C^2)
+    // (4) Compute interpolations by getting longitudes of original points
+    // la = atan2(y3,x3)
+    // (5) Rotate new points (xN0, yN0, zN0) counter-clockwise in x-z:
+    // ha = -(pi - asin(C/sqrt(A^2+B^2+C^2)))
+    // xN1 = xN0 cos ha - zN0 sin ha
+    // yN1 = yN0
+    // zN1 = xN0 sin ha + zN0 cos ha
+    // (6) Rotate new points clockwise in x-y:
+    // ra = atan2(B,A)
+    // xN2 = xN1 cos ra - yN1 sin ra
+    // yN2 = xN1 sin ra + yN1 cos ra
+    // zN2 = zN1
+    // (7) Translate new points:
+    // xN3 = xN2 - D*A
+    // yN3 = yN2 - D*B
+    // zN3 = zN2 - D*C
+
+    // First, calculate the angles and their sin/cos values
+    double A = x;
+    double B = y;
+    double C = z;
+
+    // Translation amounts
+    final double transX = -D * A;
+    final double transY = -D * B;
+    final double transZ = -D * C;
+
+    double cosRA;
+    double sinRA;
+    double cosHA;
+    double sinHA;
+
+    double magnitude = magnitude();
+    if (magnitude >= MINIMUM_RESOLUTION) {
+      final double denom = 1.0 / magnitude;
+      A *= denom;
+      B *= denom;
+      C *= denom;
+
+      // cos ra = A/sqrt(A^2+B^2+C^2)
+      // sin ra = -B/sqrt(A^2+B^2+C^2)
+      // cos (-ra) = A/sqrt(A^2+B^2+C^2)
+      // sin (-ra) = B/sqrt(A^2+B^2+C^2)
+      final double xyMagnitude = Math.sqrt(A * A + B * B);
+      if (xyMagnitude >= MINIMUM_RESOLUTION) {
+        final double xyDenom = 1.0 / xyMagnitude;
+        cosRA = A * xyDenom;
+        sinRA = -B * xyDenom;
+      } else {
+        cosRA = 1.0;
+        sinRA = 0.0;
+      }
+
+      // sin(ha) = cos(asin(C/sqrt(A^2+B^2+C^2))) = sqrt(1 - C^2/(A^2+B^2+C^2)) = sqrt(A^2+B^2)/sqrt(A^2+B^2+C^2)
+      // cos(ha) = sin(asin(C/sqrt(A^2+B^2+C^2))) = C/sqrt(A^2+B^2+C^2)
+      sinHA = xyMagnitude;
+      cosHA = C;
+    } else {
+      cosRA = 1.0;
+      sinRA = 0.0;
+      cosHA = 1.0;
+      sinHA = 0.0;
+    }
+
+    // Forward-translate the start and end points
+    final Vector modifiedStart = modify(start, transX, transY, transZ, sinRA, cosRA, sinHA, cosHA);
+    final Vector modifiedEnd = modify(end, transX, transY, transZ, sinRA, cosRA, sinHA, cosHA);
+    if (Math.abs(modifiedStart.z) >= MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("Start point was not on plane: " + modifiedStart.z);
+    if (Math.abs(modifiedEnd.z) >= MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("End point was not on plane: " + modifiedEnd.z);
+
+    // Compute the angular distance between start and end point
+    final double startAngle = Math.atan2(modifiedStart.y, modifiedStart.x);
+    final double endAngle = Math.atan2(modifiedEnd.y, modifiedEnd.x);
+
+    final double startMagnitude = Math.sqrt(modifiedStart.x * modifiedStart.x + modifiedStart.y * modifiedStart.y);
+    double delta;
+
+    double newEndAngle = endAngle;
+    while (newEndAngle < startAngle) {
+      newEndAngle += Math.PI * 2.0;
+    }
+
+    if (newEndAngle - startAngle <= Math.PI) {
+      delta = newEndAngle - startAngle;
+    } else {
+      double newStartAngle = startAngle;
+      while (newStartAngle < endAngle) {
+        newStartAngle += Math.PI * 2.0;
+      }
+      delta = newStartAngle - endAngle;
+    }
+
+    final GeoPoint[] returnValues = new GeoPoint[proportions.length];
+    for (int i = 0; i < returnValues.length; i++) {
+      final double newAngle = startAngle + proportions[i] * delta;
+      final double sinNewAngle = Math.sin(newAngle);
+      final double cosNewAngle = Math.cos(newAngle);
+      final Vector newVector = new Vector(cosNewAngle * startMagnitude, sinNewAngle * startMagnitude, 0.0);
+      returnValues[i] = reverseModify(newVector, transX, transY, transZ, sinRA, cosRA, sinHA, cosHA);
+    }
+
+    return returnValues;
+  }
+
+  /**
+   * Modify a point to produce a vector in translated/rotated space.
+   * @param start is the start point.
+   * @param transX is the translation x value.
+   * @param transY is the translation y value.
+   * @param transZ is the translation z value.
+   * @param sinRA is the sine of the ascension angle.
+   * @param cosRA is the cosine of the ascension angle.
+   * @param sinHA is the sine of the height angle.
+   * @param cosHA is the cosine of the height angle.
+   * @return the modified point.
+   */
+  protected static Vector modify(final GeoPoint start, final double transX, final double transY, final double transZ,
+                                 final double sinRA, final double cosRA, final double sinHA, final double cosHA) {
+    return start.translate(transX, transY, transZ).rotateXY(sinRA, cosRA).rotateXZ(sinHA, cosHA);
+  }
+
+  /**
+   * Reverse modify a point to produce a GeoPoint in normal space.
+   * @param point is the translated point.
+   * @param transX is the translation x value.
+   * @param transY is the translation y value.
+   * @param transZ is the translation z value.
+   * @param sinRA is the sine of the ascension angle.
+   * @param cosRA is the cosine of the ascension angle.
+   * @param sinHA is the sine of the height angle.
+   * @param cosHA is the cosine of the height angle.
+   * @return the original point.
+   */
+  protected static GeoPoint reverseModify(final Vector point, final double transX, final double transY, final double transZ,
+                                          final double sinRA, final double cosRA, final double sinHA, final double cosHA) {
+    final Vector result = point.rotateXZ(-sinHA, cosHA).rotateXY(-sinRA, cosRA).translate(-transX, -transY, -transZ);
+    return new GeoPoint(result.x, result.y, result.z);
+  }
+
+  /**
+   * Public version of findIntersections.
+   * @param planetModel is the planet model.
+   * @param q is the plane to intersect with.
+   * @param bounds are the bounds to consider to determine legal intersection points.
+   * @return the set of legal intersection points.
+   */
+  public GeoPoint[] findIntersections(final PlanetModel planetModel, final Plane q, final Membership... bounds) {
+    if (isNumericallyIdentical(q)) {
+      return null;
+    }
+    return findIntersections(planetModel, q, bounds, NO_BOUNDS);
+  }
+  
+  /**
+   * Find the intersection points between two planes, given a set of bounds.
+   *
+   * @param planetModel is the planet model to use in finding points.
+   * @param q          is the plane to intersect with.
+   * @param bounds     is the set of bounds.
+   * @param moreBounds is another set of bounds.
+   * @return the intersection point(s) on the unit sphere, if there are any.
+   */
+  protected GeoPoint[] findIntersections(final PlanetModel planetModel, final Plane q, final Membership[] bounds, final Membership[] moreBounds) {
+    //System.err.println("Looking for intersection between plane "+this+" and plane "+q+" within bounds");
+    // Unnormalized, unchecked...
+    final Vector lineVector = new Vector(y * q.z - z * q.y, z * q.x - x * q.z, x * q.y - y * q.x);
+    if (Math.abs(lineVector.x) < MINIMUM_RESOLUTION && Math.abs(lineVector.y) < MINIMUM_RESOLUTION && Math.abs(lineVector.z) < MINIMUM_RESOLUTION) {
+      // Degenerate case: parallel planes
+      //System.err.println(" planes are parallel - no intersection");
+      return NO_POINTS;
+    }
+
+    // The line will have the equation: A t + A0 = x, B t + B0 = y, C t + C0 = z.
+    // We have A, B, and C.  In order to come up with A0, B0, and C0, we need to find a point that is on both planes.
+    // To do this, we find the largest vector value (either x, y, or z), and look for a point that solves both plane equations
+    // simultaneous.  For example, let's say that the vector is (0.5,0.5,1), and the two plane equations are:
+    // 0.7 x + 0.3 y + 0.1 z + 0.0 = 0
+    // and
+    // 0.9 x - 0.1 y + 0.2 z + 4.0 = 0
+    // Then we'd pick z = 0, so the equations to solve for x and y would be:
+    // 0.7 x + 0.3y = 0.0
+    // 0.9 x - 0.1y = -4.0
+    // ... which can readily be solved using standard linear algebra.  Generally:
+    // Q0 x + R0 y = S0
+    // Q1 x + R1 y = S1
+    // ... can be solved by Cramer's rule:
+    // x = det(S0 R0 / S1 R1) / det(Q0 R0 / Q1 R1)
+    // y = det(Q0 S0 / Q1 S1) / det(Q0 R0 / Q1 R1)
+    // ... where det( a b / c d ) = ad - bc, so:
+    // x = (S0 * R1 - R0 * S1) / (Q0 * R1 - R0 * Q1)
+    // y = (Q0 * S1 - S0 * Q1) / (Q0 * R1 - R0 * Q1)
+    double x0;
+    double y0;
+    double z0;
+    // We try to maximize the determinant in the denominator
+    final double denomYZ = this.y * q.z - this.z * q.y;
+    final double denomXZ = this.x * q.z - this.z * q.x;
+    final double denomXY = this.x * q.y - this.y * q.x;
+    if (Math.abs(denomYZ) >= Math.abs(denomXZ) && Math.abs(denomYZ) >= Math.abs(denomXY)) {
+      // X is the biggest, so our point will have x0 = 0.0
+      if (Math.abs(denomYZ) < MINIMUM_RESOLUTION_SQUARED) {
+        //System.err.println(" Denominator is zero: no intersection");
+        return NO_POINTS;
+      }
+      final double denom = 1.0 / denomYZ;
+      x0 = 0.0;
+      y0 = (-this.D * q.z - this.z * -q.D) * denom;
+      z0 = (this.y * -q.D + this.D * q.y) * denom;
+    } else if (Math.abs(denomXZ) >= Math.abs(denomXY) && Math.abs(denomXZ) >= Math.abs(denomYZ)) {
+      // Y is the biggest, so y0 = 0.0
+      if (Math.abs(denomXZ) < MINIMUM_RESOLUTION_SQUARED) {
+        //System.err.println(" Denominator is zero: no intersection");
+        return NO_POINTS;
+      }
+      final double denom = 1.0 / denomXZ;
+      x0 = (-this.D * q.z - this.z * -q.D) * denom;
+      y0 = 0.0;
+      z0 = (this.x * -q.D + this.D * q.x) * denom;
+    } else {
+      // Z is the biggest, so Z0 = 0.0
+      if (Math.abs(denomXY) < MINIMUM_RESOLUTION_SQUARED) {
+        //System.err.println(" Denominator is zero: no intersection");
+        return NO_POINTS;
+      }
+      final double denom = 1.0 / denomXY;
+      x0 = (-this.D * q.y - this.y * -q.D) * denom;
+      y0 = (this.x * -q.D + this.D * q.x) * denom;
+      z0 = 0.0;
+    }
+
+    // Once an intersecting line is determined, the next step is to intersect that line with the ellipsoid, which
+    // will yield zero, one, or two points.
+    // The ellipsoid equation: 1,0 = x^2/a^2 + y^2/b^2 + z^2/c^2
+    // 1.0 = (At+A0)^2/a^2 + (Bt+B0)^2/b^2 + (Ct+C0)^2/c^2
+    // A^2 t^2 / a^2 + 2AA0t / a^2 + A0^2 / a^2 + B^2 t^2 / b^2 + 2BB0t / b^2 + B0^2 / b^2 + C^2 t^2 / c^2 + 2CC0t / c^2 + C0^2 / c^2  - 1,0 = 0.0
+    // [A^2 / a^2 + B^2 / b^2 + C^2 / c^2] t^2 + [2AA0 / a^2 + 2BB0 / b^2 + 2CC0 / c^2] t + [A0^2 / a^2 + B0^2 / b^2 + C0^2 / c^2 - 1,0] = 0.0
+    // Use the quadratic formula to determine t values and candidate point(s)
+    final double A = lineVector.x * lineVector.x * planetModel.inverseAbSquared +
+      lineVector.y * lineVector.y * planetModel.inverseAbSquared +
+      lineVector.z * lineVector.z * planetModel.inverseCSquared;
+    final double B = 2.0 * (lineVector.x * x0 * planetModel.inverseAbSquared + lineVector.y * y0 * planetModel.inverseAbSquared + lineVector.z * z0 * planetModel.inverseCSquared);
+    final double C = x0 * x0 * planetModel.inverseAbSquared + y0 * y0 * planetModel.inverseAbSquared + z0 * z0 * planetModel.inverseCSquared - 1.0;
+
+    final double BsquaredMinus = B * B - 4.0 * A * C;
+    if (Math.abs(BsquaredMinus) < MINIMUM_RESOLUTION_SQUARED) {
+      //System.err.println(" One point of intersection");
+      final double inverse2A = 1.0 / (2.0 * A);
+      // One solution only
+      final double t = -B * inverse2A;
+      GeoPoint point = new GeoPoint(lineVector.x * t + x0, lineVector.y * t + y0, lineVector.z * t + z0);
+      //System.err.println("  point: "+point);
+      //verifyPoint(planetModel, point, q);
+      if (point.isWithin(bounds, moreBounds))
+        return new GeoPoint[]{point};
+      return NO_POINTS;
+    } else if (BsquaredMinus > 0.0) {
+      //System.err.println(" Two points of intersection");
+      final double inverse2A = 1.0 / (2.0 * A);
+      // Two solutions
+      final double sqrtTerm = Math.sqrt(BsquaredMinus);
+      final double t1 = (-B + sqrtTerm) * inverse2A;
+      final double t2 = (-B - sqrtTerm) * inverse2A;
+      GeoPoint point1 = new GeoPoint(lineVector.x * t1 + x0, lineVector.y * t1 + y0, lineVector.z * t1 + z0);
+      GeoPoint point2 = new GeoPoint(lineVector.x * t2 + x0, lineVector.y * t2 + y0, lineVector.z * t2 + z0);
+      //verifyPoint(planetModel, point1, q);
+      //verifyPoint(planetModel, point2, q);
+      //System.err.println("  "+point1+" and "+point2);
+      if (point1.isWithin(bounds, moreBounds)) {
+        if (point2.isWithin(bounds, moreBounds))
+          return new GeoPoint[]{point1, point2};
+        return new GeoPoint[]{point1};
+      }
+      if (point2.isWithin(bounds, moreBounds))
+        return new GeoPoint[]{point2};
+      return NO_POINTS;
+    } else {
+      //System.err.println(" no solutions - no intersection");
+      return NO_POINTS;
+    }
+  }
+
+  /*
+  protected void verifyPoint(final PlanetModel planetModel, final GeoPoint point, final Plane q) {
+    if (!evaluateIsZero(point))
+      throw new RuntimeException("Intersection point not on original plane; point="+point+", plane="+this);
+    if (!q.evaluateIsZero(point))
+      throw new RuntimeException("Intersection point not on intersected plane; point="+point+", plane="+q);
+    if (Math.abs(point.x * point.x * planetModel.inverseASquared + point.y * point.y * planetModel.inverseBSquared + point.z * point.z * planetModel.inverseCSquared - 1.0) >= MINIMUM_RESOLUTION) 
+      throw new RuntimeException("Intersection point not on ellipsoid; point="+point);
+  }
+  */
+
+  /**
+   * Accumulate (x,y,z) bounds information for this plane, intersected with the unit sphere.
+   * Updates min/max information, using max/min points found
+   * within the specified bounds.
+   *
+   * @param planetModel is the planet model to use in determining bounds.
+   * @param boundsInfo is the xyz info to update with additional bounding information.
+   * @param bounds     are the surfaces delineating what's inside the shape.
+   */
+  public void recordBounds(final PlanetModel planetModel, final XYZBounds boundsInfo, final Membership... bounds) {
+    // Basic plan is to do three intersections of the plane and the planet.
+    // For min/max x, we intersect a vertical plane such that y = 0.
+    // For min/max y, we intersect a vertical plane such that x = 0.
+    // For min/max z, we intersect a vertical plane that is chosen to go through the high point of the arc.
+    // For clarity, load local variables with good names
+    final double A = this.x;
+    final double B = this.y;
+    final double C = this.z;
+
+    // Do Z.  This can be done simply because it is symmetrical.
+    if (!boundsInfo.isSmallestMinZ(planetModel) || !boundsInfo.isLargestMaxZ(planetModel)) {
+      //System.err.println("    computing Z bound");
+      // Compute Z bounds for this arc
+      // With ellipsoids, we really have only one viable way to do this computation.
+      // Specifically, we compute an appropriate vertical plane, based on the current plane's x-y orientation, and
+      // then intersect it with this one and with the ellipsoid.  This gives us zero, one, or two points to use
+      // as bounds.
+      // There is one special case: horizontal circles.  These require TWO vertical planes: one for the x, and one for
+      // the y, and we use all four resulting points in the bounds computation.
+      if ((Math.abs(A) >= MINIMUM_RESOLUTION || Math.abs(B) >= MINIMUM_RESOLUTION)) {
+        // NOT a degenerate case
+        //System.err.println("    not degenerate");
+        final Plane normalizedZPlane = constructNormalizedZPlane(A,B);
+        final GeoPoint[] points = findIntersections(planetModel, normalizedZPlane, bounds, NO_BOUNDS);
+        for (final GeoPoint point : points) {
+          assert planetModel.pointOnSurface(point);
+          //System.err.println("      Point = "+point+"; this.evaluate(point)="+this.evaluate(point)+"; normalizedZPlane.evaluate(point)="+normalizedZPlane.evaluate(point));
+          addPoint(boundsInfo, bounds, point);
+        }
+      } else {
+        // Since a==b==0, any plane including the Z axis suffices.
+        //System.err.println("      Perpendicular to z");
+        final GeoPoint[] points = findIntersections(planetModel, normalYPlane, NO_BOUNDS, NO_BOUNDS);
+        boundsInfo.addZValue(points[0]);
+      }
+    }
+
+    // First, compute common subexpressions
+    final double k = 1.0 / ((x*x + y*y)*planetModel.ab*planetModel.ab + z*z*planetModel.c*planetModel.c);
+    final double abSquared = planetModel.ab * planetModel.ab;
+    final double cSquared = planetModel.c * planetModel.c;
+    final double ASquared = A * A;
+    final double BSquared = B * B;
+    final double CSquared = C * C;
+    
+    final double r = 2.0*D*k;
+    final double rSquared = r * r;
+    
+    if (!boundsInfo.isSmallestMinX(planetModel) || !boundsInfo.isLargestMaxX(planetModel)) {
+      // For min/max x, we need to use lagrange multipliers.
+      //
+      // For this, we need grad(F(x,y,z)) = (dF/dx, dF/dy, dF/dz).
+      //
+      // Minimize and maximize f(x,y,z) = x, with respect to g(x,y,z) = Ax + By + Cz - D and h(x,y,z) = x^2/ab^2 + y^2/ab^2 + z^2/c^2 - 1
+      //
+      // grad(f(x,y,z)) = (1,0,0)
+      // grad(g(x,y,z)) = (A,B,C)
+      // grad(h(x,y,z)) = (2x/ab^2,2y/ab^2,2z/c^2)
+      //
+      // Equations we need to simultaneously solve:
+      // 
+      // grad(f(x,y,z)) = l * grad(g(x,y,z)) + m * grad(h(x,y,z))
+      // g(x,y,z) = 0
+      // h(x,y,z) = 0
+      // 
+      // Equations:
+      // 1 = l*A + m*2x/ab^2
+      // 0 = l*B + m*2y/ab^2
+      // 0 = l*C + m*2z/c^2
+      // Ax + By + Cz + D = 0
+      // x^2/ab^2 + y^2/ab^2 + z^2/c^2 - 1 = 0
+      // 
+      // Solve for x,y,z in terms of (l, m):
+      // 
+      // x = ((1 - l*A) * ab^2 ) / (2 * m)
+      // y = (-l*B * ab^2) / ( 2 * m)
+      // z = (-l*C * c^2)/ (2 * m)
+      // 
+      // Two equations, two unknowns:
+      // 
+      // A * (((1 - l*A) * ab^2 ) / (2 * m)) + B * ((-l*B * ab^2) / ( 2 * m)) + C * ((-l*C * c^2)/ (2 * m)) + D = 0
+      // 
+      // and
+      // 
+      // (((1 - l*A) * ab^2 ) / (2 * m))^2/ab^2 + ((-l*B * ab^2) / ( 2 * m))^2/ab^2 + ((-l*C * c^2)/ (2 * m))^2/c^2 - 1 = 0
+      // 
+      // Simple: solve for l and m, then find x from it.
+      // 
+      // (a) Use first equation to find l in terms of m.
+      // 
+      // A * (((1 - l*A) * ab^2 ) / (2 * m)) + B * ((-l*B * ab^2) / ( 2 * m)) + C * ((-l*C * c^2)/ (2 * m)) + D = 0
+      // A * ((1 - l*A) * ab^2 ) + B * (-l*B * ab^2) + C * (-l*C * c^2) + D * 2 * m = 0
+      // A * ab^2 - l*A^2* ab^2 - B^2 * l * ab^2 - C^2 * l * c^2 + D * 2 * m = 0
+      // - l *(A^2* ab^2 + B^2 * ab^2 + C^2 * c^2) + (A * ab^2 + D * 2 * m) = 0
+      // l = (A * ab^2 + D * 2 * m) / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
+      // l = A * ab^2 / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2) + m * 2 * D / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
+      // 
+      // For convenience:
+      // 
+      // k = 1.0 / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
+      // 
+      // Then:
+      // 
+      // l = A * ab^2 * k + m * 2 * D * k
+      // l = k * (A*ab^2 + m*2*D)
+      //
+      // For further convenience:
+      //
+      // q = A*ab^2*k
+      // r = 2*D*k
+      //
+      // l = (r*m + q)
+      // l^2 = (r^2 * m^2 + 2*r*m*q + q^2)
+      // 
+      // (b) Simplify the second equation before substitution
+      // 
+      // (((1 - l*A) * ab^2 ) / (2 * m))^2/ab^2 + ((-l*B * ab^2) / ( 2 * m))^2/ab^2 + ((-l*C * c^2)/ (2 * m))^2/c^2 - 1 = 0
+      // ((1 - l*A) * ab^2 )^2/ab^2 + (-l*B * ab^2)^2/ab^2 + (-l*C * c^2)^2/c^2 = 4 * m^2
+      // (1 - l*A)^2 * ab^2 + (-l*B)^2 * ab^2 + (-l*C)^2 * c^2 = 4 * m^2
+      // (1 - 2*l*A + l^2*A^2) * ab^2 + l^2*B^2 * ab^2 + l^2*C^2 * c^2 = 4 * m^2
+      // ab^2 - 2*A*ab^2*l + A^2*ab^2*l^2 + B^2*ab^2*l^2 + C^2*c^2*l^2 - 4*m^2 = 0
+      // 
+      // (c) Substitute for l, l^2
+      //
+      // ab^2 - 2*A*ab^2*(r*m + q) + A^2*ab^2*(r^2 * m^2 + 2*r*m*q + q^2) + B^2*ab^2*(r^2 * m^2 + 2*r*m*q + q^2) + C^2*c^2*(r^2 * m^2 + 2*r*m*q + q^2) - 4*m^2 = 0
+      // ab^2 - 2*A*ab^2*r*m - 2*A*ab^2*q + A^2*ab^2*r^2*m^2 + 2*A^2*ab^2*r*q*m +
+      //        A^2*ab^2*q^2 + B^2*ab^2*r^2*m^2 + 2*B^2*ab^2*r*q*m + B^2*ab^2*q^2 + C^2*c^2*r^2*m^2 + 2*C^2*c^2*r*q*m + C^2*c^2*q^2 - 4*m^2 = 0
+      //
+      // (d) Group
+      //
+      // m^2 * [A^2*ab^2*r^2 + B^2*ab^2*r^2 + C^2*c^2*r^2 - 4] +
+      // m * [- 2*A*ab^2*r + 2*A^2*ab^2*r*q + 2*B^2*ab^2*r*q + 2*C^2*c^2*r*q] +
+      // [ab^2 - 2*A*ab^2*q + A^2*ab^2*q^2 + B^2*ab^2*q^2 + C^2*c^2*q^2]  =  0
+      
+      //System.err.println("    computing X bound");
+      
+      // Useful subexpressions for this bound
+      final double q = A*abSquared*k;
+      final double qSquared = q * q;
+
+      // Quadratic equation
+      final double a = ASquared*abSquared*rSquared + BSquared*abSquared*rSquared + CSquared*cSquared*rSquared - 4.0;
+      final double b = - 2.0*A*abSquared*r + 2.0*ASquared*abSquared*r*q + 2.0*BSquared*abSquared*r*q + 2.0*CSquared*cSquared*r*q;
+      final double c = abSquared - 2.0*A*abSquared*q + ASquared*abSquared*qSquared + BSquared*abSquared*qSquared + CSquared*cSquared*qSquared;
+      
+      if (Math.abs(a) >= MINIMUM_RESOLUTION_SQUARED) {
+        final double sqrtTerm = b*b - 4.0*a*c;
+        if (Math.abs(sqrtTerm) < MINIMUM_RESOLUTION_SQUARED) {
+          // One solution
+          final double m = -b / (2.0 * a);
+          final double l = r * m + q;
+          // x = ((1 - l*A) * ab^2 ) / (2 * m)
+          // y = (-l*B * ab^2) / ( 2 * m)
+          // z = (-l*C * c^2)/ (2 * m)
+          final double denom0 = 0.5 / m;
+          final GeoPoint thePoint = new GeoPoint((1.0-l*A) * abSquared * denom0, -l*B * abSquared * denom0, -l*C * cSquared * denom0);
+          //Math is not quite accurate enough for this
+          //assert planetModel.pointOnSurface(thePoint): "Point: "+thePoint+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
+          //  (thePoint.x*thePoint.x*planetModel.inverseAb*planetModel.inverseAb + thePoint.y*thePoint.y*planetModel.inverseAb*planetModel.inverseAb + thePoint.z*thePoint.z*planetModel.inverseC*planetModel.inverseC);
+          //assert evaluateIsZero(thePoint): "Evaluation of point: "+evaluate(thePoint);
+          addPoint(boundsInfo, bounds, thePoint);
+        } else if (sqrtTerm > 0.0) {
+          // Two solutions
+          final double sqrtResult = Math.sqrt(sqrtTerm);
+          final double commonDenom = 0.5/a;
+          final double m1 = (-b + sqrtResult) * commonDenom;
+          assert Math.abs(a * m1 * m1 + b * m1 + c) < MINIMUM_RESOLUTION;
+          final double m2 = (-b - sqrtResult) * commonDenom;
+          assert Math.abs(a * m2 * m2 + b * m2 + c) < MINIMUM_RESOLUTION;
+          final double l1 = r * m1 + q;
+          final double l2 = r * m2 + q;
+          // x = ((1 - l*A) * ab^2 ) / (2 * m)
+          // y = (-l*B * ab^2) / ( 2 * m)
+          // z = (-l*C * c^2)/ (2 * m)
+          final double denom1 = 0.5 / m1;
+          final double denom2 = 0.5 / m2;
+          final GeoPoint thePoint1 = new GeoPoint((1.0-l1*A) * abSquared * denom1, -l1*B * abSquared * denom1, -l1*C * cSquared * denom1);
+          final GeoPoint thePoint2 = new GeoPoint((1.0-l2*A) * abSquared * denom2, -l2*B * abSquared * denom2, -l2*C * cSquared * denom2);
+          //Math is not quite accurate enough for this
+          //assert planetModel.pointOnSurface(thePoint1): "Point1: "+thePoint1+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
+          //  (thePoint1.x*thePoint1.x*planetModel.inverseAb*planetModel.inverseAb + thePoint1.y*thePoint1.y*planetModel.inverseAb*planetModel.inverseAb + thePoint1.z*thePoint1.z*planetModel.inverseC*planetModel.inverseC);
+          //assert planetModel.pointOnSurface(thePoint2): "Point1: "+thePoint2+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
+          //  (thePoint2.x*thePoint2.x*planetModel.inverseAb*planetModel.inverseAb + thePoint2.y*thePoint2.y*planetModel.inverseAb*planetModel.inverseAb + thePoint2.z*thePoint2.z*planetModel.inverseC*planetModel.inverseC);
+          //assert evaluateIsZero(thePoint1): "Evaluation of point1: "+evaluate(thePoint1);
+          //assert evaluateIsZero(thePoint2): "Evaluation of point2: "+evaluate(thePoint2);
+          addPoint(boundsInfo, bounds, thePoint1);
+          addPoint(boundsInfo, bounds, thePoint2);
+        } else {
+          // No solutions
+        }
+      } else if (Math.abs(b) > MINIMUM_RESOLUTION_SQUARED) {
+        //System.err.println("Not x quadratic");
+        // a = 0, so m = - c / b
+        final double m = -c / b;
+        final double l = r * m + q;
+        // x = ((1 - l*A) * ab^2 ) / (2 * m)
+        // y = (-l*B * ab^2) / ( 2 * m)
+        // z = (-l*C * c^2)/ (2 * m)
+        final double denom0 = 0.5 / m;
+        final GeoPoint thePoint = new GeoPoint((1.0-l*A) * abSquared * denom0, -l*B * abSquared * denom0, -l*C * cSquared * denom0);
+        //Math is not quite accurate enough for this
+        //assert planetModel.pointOnSurface(thePoint): "Point: "+thePoint+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
+        //  (thePoint.x*thePoint.x*planetModel.inverseAb*planetModel.inverseAb + thePoint.y*thePoint.y*planetModel.inverseAb*planetModel.inverseAb + thePoint.z*thePoint.z*planetModel.inverseC*planetModel.inverseC);
+        //assert evaluateIsZero(thePoint): "Evaluation of point: "+evaluate(thePoint);
+        addPoint(boundsInfo, bounds, thePoint);
+      } else {
+        // Something went very wrong; a = b = 0
+      }
+    }
+    
+    // Do Y
+    if (!boundsInfo.isSmallestMinY(planetModel) || !boundsInfo.isLargestMaxY(planetModel)) {
+      // For min/max x, we need to use lagrange multipliers.
+      //
+      // For this, we need grad(F(x,y,z)) = (dF/dx, dF/dy, dF/dz).
+      //
+      // Minimize and maximize f(x,y,z) = y, with respect to g(x,y,z) = Ax + By + Cz - D and h(x,y,z) = x^2/ab^2 + y^2/ab^2 + z^2/c^2 - 1
+      //
+      // grad(f(x,y,z)) = (0,1,0)
+      // grad(g(x,y,z)) = (A,B,C)
+      // grad(h(x,y,z)) = (2x/ab^2,2y/ab^2,2z/c^2)
+      //
+      // Equations we need to simultaneously solve:
+      // 
+      // grad(f(x,y,z)) = l * grad(g(x,y,z)) + m * grad(h(x,y,z))
+      // g(x,y,z) = 0
+      // h(x,y,z) = 0
+      // 
+      // Equations:
+      // 0 = l*A + m*2x/ab^2
+      // 1 = l*B + m*2y/ab^2
+      // 0 = l*C + m*2z/c^2
+      // Ax + By + Cz + D = 0
+      // x^2/ab^2 + y^2/ab^2 + z^2/c^2 - 1 = 0
+      // 
+      // Solve for x,y,z in terms of (l, m):
+      // 
+      // x = (-l*A * ab^2 ) / (2 * m)
+      // y = ((1 - l*B) * ab^2) / ( 2 * m)
+      // z = (-l*C * c^2)/ (2 * m)
+      // 
+      // Two equations, two unknowns:
+      // 
+      // A * ((-l*A * ab^2 ) / (2 * m)) + B * (((1 - l*B) * ab^2) / ( 2 * m)) + C * ((-l*C * c^2)/ (2 * m)) + D = 0
+      // 
+      // and
+      // 
+      // ((-l*A * ab^2 ) / (2 * m))^2/ab^2 + (((1 - l*B) * ab^2) / ( 2 * m))^2/ab^2 + ((-l*C * c^2)/ (2 * m))^2/c^2 - 1 = 0
+      // 
+      // Simple: solve for l and m, then find y from it.
+      // 
+      // (a) Use first equation to find l in terms of m.
+      // 
+      // A * ((-l*A * ab^2 ) / (2 * m)) + B * (((1 - l*B) * ab^2) / ( 2 * m)) + C * ((-l*C * c^2)/ (2 * m)) + D = 0
+      // A * (-l*A * ab^2 ) + B * ((1-l*B) * ab^2) + C * (-l*C * c^2) + D * 2 * m = 0
+      // -A^2*l*ab^2 + B*ab^2 - l*B^2*ab^2 - C^2*l*c^2 + D*2*m = 0
+      // - l *(A^2* ab^2 + B^2 * ab^2 + C^2 * c^2) + (B * ab^2 + D * 2 * m) = 0
+      // l = (B * ab^2 + D * 2 * m) / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
+      // l = B * ab^2 / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2) + m * 2 * D / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
+      // 
+      // For convenience:
+      // 
+      // k = 1.0 / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
+      // 
+      // Then:
+      // 
+      // l = B * ab^2 * k + m * 2 * D * k
+      // l = k * (B*ab^2 + m*2*D)
+      //
+      // For further convenience:
+      //
+      // q = B*ab^2*k
+      // r = 2*D*k
+      //
+      // l = (r*m + q)
+      // l^2 = (r^2 * m^2 + 2*r*m*q + q^2)
+      // 
+      // (b) Simplify the second equation before substitution
+      // 
+      // ((-l*A * ab^2 ) / (2 * m))^2/ab^2 + (((1 - l*B) * ab^2) / ( 2 * m))^2/ab^2 + ((-l*C * c^2)/ (2 * m))^2/c^2 - 1 = 0
+      // (-l*A * ab^2 )^2/ab^2 + ((1 - l*B) * ab^2)^2/ab^2 + (-l*C * c^2)^2/c^2 = 4 * m^2
+      // (-l*A)^2 * ab^2 + (1 - l*B)^2 * ab^2 + (-l*C)^2 * c^2 = 4 * m^2
+      // l^2*A^2 * ab^2 + (1 - 2*l*B + l^2*B^2) * ab^2 + l^2*C^2 * c^2 = 4 * m^2
+      // A^2*ab^2*l^2 + ab^2 - 2*B*ab^2*l + B^2*ab^2*l^2 + C^2*c^2*l^2 - 4*m^2 = 0
+      // 
+      // (c) Substitute for l, l^2
+      //
+      // A^2*ab^2*(r^2 * m^2 + 2*r*m*q + q^2) + ab^2 - 2*B*ab^2*(r*m + q) + B^2*ab^2*(r^2 * m^2 + 2*r*m*q + q^2) + C^2*c^2*(r^2 * m^2 + 2*r*m*q + q^2) - 4*m^2 = 0
+      // A^2*ab^2*r^2*m^2 + 2*A^2*ab^2*r*q*m + A^2*ab^2*q^2 + ab^2 - 2*B*ab^2*r*m - 2*B*ab^2*q + B^2*ab^2*r^2*m^2 +
+      //    2*B^2*ab^2*r*q*m + B^2*ab^2*q^2 + C^2*c^2*r^2*m^2 + 2*C^2*c^2*r*q*m + C^2*c^2*q^2 - 4*m^2 = 0
+      //
+      // (d) Group
+      //
+      // m^2 * [A^2*ab^2*r^2 + B^2*ab^2*r^2 + C^2*c^2*r^2 - 4] +
+      // m * [2*A^2*ab^2*r*q - 2*B*ab^2*r + 2*B^2*ab^2*r*q + 2*C^2*c^2*r*q] +
+      // [A^2*ab^2*q^2 + ab^2 - 2*B*ab^2*q + B^2*ab^2*q^2 + C^2*c^2*q^2]  =  0
+
+      //System.err.println("    computing Y bound");
+      
+      // Useful subexpressions for this bound
+      final double q = B*abSquared*k;
+      final double qSquared = q * q;
+
+      // Quadratic equation
+      final double a = ASquared*abSquared*rSquared + BSquared*abSquared*rSquared + CSquared*cSquared*rSquared - 4.0;
+      final double b = 2.0*ASquared*abSquared*r*q - 2.0*B*abSquared*r + 2.0*BSquared*abSquared*r*q + 2.0*CSquared*cSquared*r*q;
+      final double c = ASquared*abSquared*qSquared + abSquared - 2.0*B*abSquared*q + BSquared*abSquared*qSquared + CSquared*cSquared*qSquared;
+
+      if (Math.abs(a) >= MINIMUM_RESOLUTION_SQUARED) {
+        final double sqrtTerm = b*b - 4.0*a*c;
+        if (Math.abs(sqrtTerm) < MINIMUM_RESOLUTION_SQUARED) {
+          // One solution
+          final double m = -b / (2.0 * a);
+          final double l = r * m + q;
+          // x = (-l*A * ab^2 ) / (2 * m)
+          // y = ((1.0-l*B) * ab^2) / ( 2 * m)
+          // z = (-l*C * c^2)/ (2 * m)
+          final double denom0 = 0.5 / m;
+          final GeoPoint thePoint = new GeoPoint(-l*A * abSquared * denom0, (1.0-l*B) * abSquared * denom0, -l*C * cSquared * denom0);
+          //Math is not quite accurate enough for this
+          //assert planetModel.pointOnSurface(thePoint): "Point: "+thePoint+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
+          //  (thePoint1.x*thePoint.x*planetModel.inverseAb*planetModel.inverseAb + thePoint.y*thePoint.y*planetModel.inverseAb*planetModel.inverseAb + thePoint.z*thePoint.z*planetModel.inverseC*planetModel.inverseC);
+          //assert evaluateIsZero(thePoint): "Evaluation of point: "+evaluate(thePoint);
+          addPoint(boundsInfo, bounds, thePoint);
+        } else if (sqrtTerm > 0.0) {
+          // Two solutions
+          final double sqrtResult = Math.sqrt(sqrtTerm);
+          final double commonDenom = 0.5/a;
+          final double m1 = (-b + sqrtResult) * commonDenom;
+          assert Math.abs(a * m1 * m1 + b * m1 + c) < MINIMUM_RESOLUTION;
+          final double m2 = (-b - sqrtResult) * commonDenom;
+          assert Math.abs(a * m2 * m2 + b * m2 + c) < MINIMUM_RESOLUTION;
+          final double l1 = r * m1 + q;
+          final double l2 = r * m2 + q;
+          // x = (-l*A * ab^2 ) / (2 * m)
+          // y = ((1.0-l*B) * ab^2) / ( 2 * m)
+          // z = (-l*C * c^2)/ (2 * m)
+          final double denom1 = 0.5 / m1;
+          final double denom2 = 0.5 / m2;
+          final GeoPoint thePoint1 = new GeoPoint(-l1*A * abSquared * denom1, (1.0-l1*B) * abSquared * denom1, -l1*C * cSquared * denom1);
+          final GeoPoint thePoint2 = new GeoPoint(-l2*A * abSquared * denom2, (1.0-l2*B) * abSquared * denom2, -l2*C * cSquared * denom2);
+          //Math is not quite accurate enough for this
+          //assert planetModel.pointOnSurface(thePoint1): "Point1: "+thePoint1+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
+          //  (thePoint1.x*thePoint1.x*planetModel.inverseAb*planetModel.inverseAb + thePoint1.y*thePoint1.y*planetModel.inverseAb*planetModel.inverseAb + thePoint1.z*thePoint1.z*planetModel.inverseC*planetModel.inverseC);
+          //assert planetModel.pointOnSurface(thePoint2): "Point2: "+thePoint2+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
+          //  (thePoint2.x*thePoint2.x*planetModel.inverseAb*planetModel.inverseAb + thePoint2.y*thePoint2.y*planetModel.inverseAb*planetModel.inverseAb + thePoint2.z*thePoint2.z*planetModel.inverseC*planetModel.inverseC);
+          //assert evaluateIsZero(thePoint1): "Evaluation of point1: "+evaluate(thePoint1);
+          //assert evaluateIsZero(thePoint2): "Evaluation of point2: "+evaluate(thePoint2);
+          addPoint(boundsInfo, bounds, thePoint1);
+          addPoint(boundsInfo, bounds, thePoint2);
+        } else {
+          // No solutions
+        }
+      } else if (Math.abs(b) > MINIMUM_RESOLUTION_SQUARED) {
+        // a = 0, so m = - c / b
+        final double m = -c / b;
+        final double l = r * m + q;
+        // x = ( -l*A * ab^2 ) / (2 * m)
+        // y = ((1-l*B) * ab^2) / ( 2 * m)
+        // z = (-l*C * c^2)/ (2 * m)
+        final double denom0 = 0.5 / m;
+        final GeoPoint thePoint = new GeoPoint(-l*A * abSquared * denom0, (1.0-l*B) * abSquared * denom0, -l*C * cSquared * denom0);
+        //Math is not quite accurate enough for this
+        //assert planetModel.pointOnSurface(thePoint): "Point: "+thePoint+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
+        //  (thePoint.x*thePoint.x*planetModel.inverseAb*planetModel.inverseAb + thePoint.y*thePoint.y*planetModel.inverseAb*planetModel.inverseAb + thePoint.z*thePoint.z*planetModel.inverseC*planetModel.inverseC);
+        //assert evaluateIsZero(thePoint): "Evaluation of point: "+evaluate(thePoint);
+        addPoint(boundsInfo, bounds, thePoint);
+      } else {
+        // Something went very wrong; a = b = 0
+      }
+    }
+  }
+  
+  /**
+   * Accumulate bounds information for this plane, intersected with the unit sphere.
+   * Updates both latitude and longitude information, using max/min points found
+   * within the specified bounds.
+   *
+   * @param planetModel is the planet model to use in determining bounds.
+   * @param boundsInfo is the lat/lon info to update with additional bounding information.
+   * @param bounds     are the surfaces delineating what's inside the shape.
+   */
+  public void recordBounds(final PlanetModel planetModel, final LatLonBounds boundsInfo, final Membership... bounds) {
+    // For clarity, load local variables with good names
+    final double A = this.x;
+    final double B = this.y;
+    final double C = this.z;
+
+    // Now compute latitude min/max points
+    if (!boundsInfo.checkNoTopLatitudeBound() || !boundsInfo.checkNoBottomLatitudeBound()) {
+      //System.err.println("Looking at latitude for plane "+this);
+      // With ellipsoids, we really have only one viable way to do this computation.
+      // Specifically, we compute an appropriate vertical plane, based on the current plane's x-y orientation, and
+      // then intersect it with this one and with the ellipsoid.  This gives us zero, one, or two points to use
+      // as bounds.
+      // There is one special case: horizontal circles.  These require TWO vertical planes: one for the x, and one for
+      // the y, and we use all four resulting points in the bounds computation.
+      if ((Math.abs(A) >= MINIMUM_RESOLUTION || Math.abs(B) >= MINIMUM_RESOLUTION)) {
+        // NOT a horizontal circle!
+        //System.err.println(" Not a horizontal circle");
+        final Plane verticalPlane = constructNormalizedZPlane(A,B);
+        final GeoPoint[] points = findIntersections(planetModel, verticalPlane, bounds, NO_BOUNDS);
+        for (final GeoPoint point : points) {
+          addPoint(boundsInfo, bounds, point);
+        }
+      } else {
+        // Horizontal circle.  Since a==b, any vertical plane suffices.
+        final GeoPoint[] points = findIntersections(planetModel, normalXPlane, NO_BOUNDS, NO_BOUNDS);
+        boundsInfo.addZValue(points[0]);
+      }
+      //System.err.println("Done latitude bounds");
+    }
+
+    // First, figure out our longitude bounds, unless we no longer need to consider that
+    if (!boundsInfo.checkNoLongitudeBound()) {
+      //System.err.println("Computing longitude bounds for "+this);
+      //System.out.println("A = "+A+" B = "+B+" C = "+C+" D = "+D);
+      // Compute longitude bounds
+
+      double a;
+      double b;
+      double c;
+
+      if (Math.abs(C) < MINIMUM_RESOLUTION) {
+        // Degenerate; the equation describes a line
+        //System.out.println("It's a zero-width ellipse");
+        // Ax + By + D = 0
+        if (Math.abs(D) >= MINIMUM_RESOLUTION) {
+          if (Math.abs(A) > Math.abs(B)) {
+            // Use equation suitable for A != 0
+            // We need to find the endpoints of the zero-width ellipse.
+            // Geometrically, we have a line segment in x-y space.  We need to locate the endpoints
+            // of that line.  But luckily, we know some things: specifically, since it is a
+            // degenerate situation in projection, the C value had to have been 0.  That
+            // means that our line's endpoints will coincide with the projected ellipse.  All we
+            // need to do then is to find the intersection of the projected ellipse and the line
+            // equation:
+            //
+            // A x + B y + D = 0
+            //
+            // Since A != 0:
+            // x = (-By - D)/A
+            //
+            // The projected ellipse:
+            // x^2/a^2 + y^2/b^2 - 1 = 0
+            // Substitute:
+            // [(-By-D)/A]^2/a^2 + y^2/b^2 -1 = 0
+            // Multiply through by A^2:
+            // [-By - D]^2/a^2 + A^2*y^2/b^2 - A^2 = 0
+            // Multiply out:
+            // B^2*y^2/a^2 + 2BDy/a^2 + D^2/a^2 + A^2*y^2/b^2 - A^2 = 0
+            // Group:
+            // y^2 * [B^2/a^2 + A^2/b^2] + y [2BD/a^2] + [D^2/a^2-A^2] = 0
+
+            a = B * B * planetModel.inverseAbSquared + A * A * planetModel.inverseAbSquared;
+            b = 2.0 * B * D * planetModel.inverseAbSquared;
+            c = D * D * planetModel.inverseAbSquared - A * A;
+
+            double sqrtClause = b * b - 4.0 * a * c;
+
+            if (Math.abs(sqrtClause) < MINIMUM_RESOLUTION_SQUARED) {
+              double y0 = -b / (2.0 * a);
+              double x0 = (-D - B * y0) / A;
+              double z0 = 0.0;
+              addPoint(boundsInfo, bounds, new GeoPoint(x0, y0, z0));
+            } else if (sqrtClause > 0.0) {
+              double sqrtResult = Math.sqrt(sqrtClause);
+              double denom = 1.0 / (2.0 * a);
+              double Hdenom = 1.0 / A;
+
+              double y0a = (-b + sqrtResult) * denom;
+              double y0b = (-b - sqrtResult) * denom;
+
+              double x0a = (-D - B * y0a) * Hdenom;
+              double x0b = (-D - B * y0b) * Hdenom;
+
+              double z0a = 0.0;
+              double z0b = 0.0;
+
+              addPoint(boundsInfo, bounds, new GeoPoint(x0a, y0a, z0a));
+              addPoint(boundsInfo, bounds, new GeoPoint(x0b, y0b, z0b));
+            }
+
+          } else {
+            // Use equation suitable for B != 0
+            // Since I != 0, we rewrite:
+            // y = (-Ax - D)/B
+            a = B * B * planetModel.inverseAbSquared + A * A * planetModel.inverseAbSquared;
+            b = 2.0 * A * D * planetModel.inverseAbSquared;
+            c = D * D * planetModel.inverseAbSquared - B * B;
+
+            double sqrtClause = b * b - 4.0 * a * c;
+
+            if (Math.abs(sqrtClause) < MINIMUM_RESOLUTION_SQUARED) {
+              double x0 = -b / (2.0 * a);
+              double y0 = (-D - A * x0) / B;
+              double z0 = 0.0;
+              addPoint(boundsInfo, bounds, new GeoPoint(x0, y0, z0));
+            } else if (sqrtClause > 0.0) {
+              double sqrtResult = Math.sqrt(sqrtClause);
+              double denom = 1.0 / (2.0 * a);
+              double Idenom = 1.0 / B;
+
+              double x0a = (-b + sqrtResult) * denom;
+              double x0b = (-b - sqrtResult) * denom;
+              double y0a = (-D - A * x0a) * Idenom;
+              double y0b = (-D - A * x0b) * Idenom;
+              double z0a = 0.0;
+              double z0b = 0.0;
+
+              addPoint(boundsInfo, bounds, new GeoPoint(x0a, y0a, z0a));
+              addPoint(boundsInfo, bounds, new GeoPoint(x0b, y0b, z0b));
+            }
+          }
+        }
+
+      } else {
+        //System.err.println("General longitude bounds...");
+
+        // NOTE WELL: The x,y,z values generated here are NOT on the unit sphere.
+        // They are for lat/lon calculation purposes only.  x-y is meant to be used for longitude determination,
+        // and z for latitude, and that's all the values are good for.
+
+        // (1) Intersect the plane and the ellipsoid, and project the results into the x-y plane:
+        // From plane:
+        // z = (-Ax - By - D) / C
+        // From ellipsoid:
+        // x^2/a^2 + y^2/b^2 + [(-Ax - By - D) / C]^2/c^2 = 1
+        // Simplify/expand:
+        // C^2*x^2/a^2 + C^2*y^2/b^2 + (-Ax - By - D)^2/c^2 = C^2
+        //
+        // x^2 * C^2/a^2 + y^2 * C^2/b^2 + x^2 * A^2/c^2 + ABxy/c^2 + ADx/c^2 + ABxy/c^2 + y^2 * B^2/c^2 + BDy/c^2 + ADx/c^2 + BDy/c^2 + D^2/c^2 = C^2
+        // Group:
+        // [A^2/c^2 + C^2/a^2] x^2 + [B^2/c^2 + C^2/b^2] y^2 + [2AB/c^2]xy + [2AD/c^2]x + [2BD/c^2]y + [D^2/c^2-C^2] = 0
+        // For convenience, introduce post-projection coefficient variables to make life easier.
+        // E x^2 + F y^2 + G xy + H x + I y + J = 0
+        double E = A * A * planetModel.inverseCSquared + C * C * planetModel.inverseAbSquared;
+        double F = B * B * planetModel.inverseCSquared + C * C * planetModel.inverseAbSquared;
+        double G = 2.0 * A * B * planetModel.inverseCSquared;
+        double H = 2.0 * A * D * planetModel.inverseCSquared;
+        double I = 2.0 * B * D * planetModel.inverseCSquared;
+        double J = D * D * planetModel.inverseCSquared - C * C;
+
+        //System.err.println("E = " + E + " F = " + F + " G = " + G + " H = "+ H + " I = " + I + " J = " + J);
+
+        // Check if the origin is within, by substituting x = 0, y = 0 and seeing if less than zero
+        if (Math.abs(J) >= MINIMUM_RESOLUTION && J > 0.0) {
+          // The derivative of the curve above is:
+          // 2Exdx + 2Fydy + G(xdy+ydx) + Hdx + Idy = 0
+          // (2Ex + Gy + H)dx + (2Fy + Gx + I)dy = 0
+          // dy/dx = - (2Ex + Gy + H) / (2Fy + Gx + I)
+          //
+          // The equation of a line going through the origin with the slope dy/dx is:
+          // y = dy/dx x
+          // y = - (2Ex + Gy + H) / (2Fy + Gx + I)  x
+          // Rearrange:
+          // (2Fy + Gx + I) y + (2Ex + Gy + H) x = 0
+          // 2Fy^2 + Gxy + Iy + 2Ex^2 + Gxy + Hx = 0
+          // 2Ex^2 + 2Fy^2 + 2Gxy + Hx + Iy = 0
+          //
+          // Multiply the original equation by 2:
+          // 2E x^2 + 2F y^2 + 2G xy + 2H x + 2I y + 2J = 0
+          // Subtract one from the other, to remove the high-order terms:
+          // Hx + Iy + 2J = 0
+          // Now, we can substitute either x = or y = into the derivative equation, or into the original equation.
+          // But we will need to base this on which coefficient is non-zero
+
+          if (Math.abs(H) > Math.abs(I)) {
+            //System.err.println(" Using the y quadratic");
+            // x = (-2J - Iy)/H
+
+            // Plug into the original equation:
+            // E [(-2J - Iy)/H]^2 + F y^2 + G [(-2J - Iy)/H]y + H [(-2J - Iy)/H] + I y + J = 0
+            // E [(-2J - Iy)/H]^2 + F y^2 + G [(-2J - Iy)/H]y - J = 0
+            // Same equation as derivative equation, except for a factor of 2!  So it doesn't matter which we pick.
+
+            // Plug into derivative equation:
+            // 2E[(-2J - Iy)/H]^2 + 2Fy^2 + 2G[(-2J - Iy)/H]y + H[(-2J - Iy)/H] + Iy = 0
+            // 2E[(-2J - Iy)/H]^2 + 2Fy^2 + 2G[(-2J - Iy)/H]y - 2J = 0
+            // E[(-2J - Iy)/H]^2 + Fy^2 + G[(-2J - Iy)/H]y - J = 0
+
+            // Multiply by H^2 to make manipulation easier
+            // E[(-2J - Iy)]^2 + F*H^2*y^2 + GH[(-2J - Iy)]y - J*H^2 = 0
+            // Do the square
+            // E[4J^2 + 4IJy + I^2*y^2] + F*H^2*y^2 + GH(-2Jy - I*y^2) - J*H^2 = 0
+
+            // Multiply it out
+            // 4E*J^2 + 4EIJy + E*I^2*y^2 + H^2*Fy^2 - 2GHJy - GH*I*y^2 - J*H^2 = 0
+            // Group:
+            // y^2 [E*I^2 - GH*I + F*H^2] + y [4EIJ - 2GHJ] + [4E*J^2 - J*H^2] = 0
+
+            a = E * I * I - G * H * I + F * H * H;
+            b = 4.0 * E * I * J - 2.0 * G * H * J;
+            c = 4.0 * E * J * J - J * H * H;
+
+            //System.out.println("a="+a+" b="+b+" c="+c);
+            double sqrtClause = b * b - 4.0 * a * c;
+            //System.out.println("sqrtClause="+sqrtClause);
+
+            if (Math.abs(sqrtClause) < MINIMUM_RESOLUTION_CUBED) {
+              //System.err.println(" One solution");
+              double y0 = -b / (2.0 * a);
+              double x0 = (-2.0 * J - I * y0) / H;
+              double z0 = (-A * x0 - B * y0 - D) / C;
+
+              addPoint(boundsInfo, bounds, new GeoPoint(x0, y0, z0));
+            } else if (sqrtClause > 0.0) {
+              //System.err.println(" Two solutions");
+              double sqrtResult = Math.sqrt(sqrtClause);
+              double denom = 1.0 / (2.0 * a);
+              double Hdenom = 1.0 / H;
+              double Cdenom = 1.0 / C;
+
+              double y0a = (-b + sqrtResult) * denom;
+              double y0b = (-b - sqrtResult) * denom;
+              double x0a = (-2.0 * J - I * y0a) * Hdenom;
+              double x0b = (-2.0 * J - I * y0b) * Hdenom;
+              double z0a = (-A * x0a - B * y0a - D) * Cdenom;
+              double z0b = (-A * x0b - B * y0b - D) * Cdenom;
+
+              addPoint(boundsInfo, bounds, new GeoPoint(x0a, y0a, z0a));
+              addPoint(boundsInfo, bounds, new GeoPoint(x0b, y0b, z0b));
+            }
+
+          } else {
+            //System.err.println(" Using the x quadratic");
+            // y = (-2J - Hx)/I
+
+            // Plug into the original equation:
+            // E x^2 + F [(-2J - Hx)/I]^2 + G x[(-2J - Hx)/I] - J = 0
+
+            // Multiply by I^2 to make manipulation easier
+            // E * I^2 * x^2 + F [(-2J - Hx)]^2 + GIx[(-2J - Hx)] - J * I^2 = 0
+            // Do the square
+            // E * I^2 * x^2 + F [ 4J^2 + 4JHx + H^2*x^2] + GI[(-2Jx - H*x^2)] - J * I^2 = 0
+
+            // Multiply it out
+            // E * I^2 * x^2 + 4FJ^2 + 4FJHx + F*H^2*x^2 - 2GIJx - HGI*x^2 - J * I^2 = 0
+            // Group:
+            // x^2 [E*I^2 - GHI + F*H^2] + x [4FJH - 2GIJ] + [4FJ^2 - J*I^2] = 0
+
+            // E x^2 + F y^2 + G xy + H x + I y + J = 0
+
+            a = E * I * I - G * H * I + F * H * H;
+            b = 4.0 * F * H * J - 2.0 * G * I * J;
+            c = 4.0 * F * J * J - J * I * I;
+
+            //System.out.println("a="+a+" b="+b+" c="+c);
+            double sqrtClause = b * b - 4.0 * a * c;
+            //System.out.println("sqrtClause="+sqrtClause);
+            if (Math.abs(sqrtClause) < MINIMUM_RESOLUTION_CUBED) {
+              //System.err.println(" One solution; sqrt clause was "+sqrtClause);
+              double x0 = -b / (2.0 * a);
+              double y0 = (-2.0 * J - H * x0) / I;
+              double z0 = (-A * x0 - B * y0 - D) / C;
+              // Verify that x&y fulfill the equation
+              // 2Ex^2 + 2Fy^2 + 2Gxy + Hx + Iy = 0
+              addPoint(boundsInfo, bounds, new GeoPoint(x0, y0, z0));
+            } else if (sqrtClause > 0.0) {
+              //System.err.println(" Two solutions");
+              double sqrtResult = Math.sqrt(sqrtClause);
+              double denom = 1.0 / (2.0 * a);
+              double Idenom = 1.0 / I;
+              double Cdenom = 1.0 / C;
+
+              double x0a = (-b + sqrtResult) * denom;
+              double x0b = (-b - sqrtResult) * denom;
+              double y0a = (-2.0 * J - H * x0a) * Idenom;
+              double y0b = (-2.0 * J - H * x0b) * Idenom;
+              double z0a = (-A * x0a - B * y0a - D) * Cdenom;
+              double z0b = (-A * x0b - B * y0b - D) * Cdenom;
+
+              addPoint(boundsInfo, bounds, new GeoPoint(x0a, y0a, z0a));
+              addPoint(boundsInfo, bounds, new GeoPoint(x0b, y0b, z0b));
+            }
+          }
+        }
+      }
+    }
+
+  }
+
+  /** Add a point to boundsInfo if within a specifically bounded area.
+   * @param boundsInfo is the object to be modified.
+   * @param bounds is the area that the point must be within.
+   * @param point is the point.
+   */
+  protected static void addPoint(final Bounds boundsInfo, final Membership[] bounds, final GeoPoint point) {
+    // Make sure the discovered point is within the bounds
+    for (Membership bound : bounds) {
+      if (!bound.isWithin(point))
+        return;
+    }
+    // Add the point
+    boundsInfo.addPoint(point);
+  }
+
+  /** Add a point to boundsInfo if within a specifically bounded area.
+   * @param boundsInfo is the object to be modified.
+   * @param bounds is the area that the point must be within.
+   * @param x is the x value.
+   * @param y is the y value.
+   * @param z is the z value.
+   */
+  /*
+  protected static void addPoint(final Bounds boundsInfo, final Membership[] bounds, final double x, final double y, final double z) {
+    //System.err.println(" Want to add point x="+x+" y="+y+" z="+z);
+    // Make sure the discovered point is within the bounds
+    for (Membership bound : bounds) {
+      if (!bound.isWithin(x, y, z))
+        return;
+    }
+    // Add the point
+    //System.err.println("  point added");
+    //System.out.println("Adding point x="+x+" y="+y+" z="+z);
+    boundsInfo.addPoint(x, y, z);
+  }
+  */
+
+  /**
+   * Determine whether the plane intersects another plane within the
+   * bounds provided.
+   *
+   * @param planetModel is the planet model to use in determining intersection.
+   * @param q                 is the other plane.
+   * @param notablePoints     are points to look at to disambiguate cases when the two planes are identical.
+   * @param moreNotablePoints are additional points to look at to disambiguate cases when the two planes are identical.
+   * @param bounds            is one part of the bounds.
+   * @param moreBounds        are more bounds.
+   * @return true if there's an intersection.
+   */
+  public boolean intersects(final PlanetModel planetModel, final Plane q, final GeoPoint[] notablePoints, final GeoPoint[] moreNotablePoints, final Membership[] bounds, final Membership... moreBounds) {
+    //System.err.println("Does plane "+this+" intersect with plane "+q);
+    // If the two planes are identical, then the math will find no points of intersection.
+    // So a special case of this is to check for plane equality.  But that is not enough, because
+    // what we really need at that point is to determine whether overlap occurs between the two parts of the intersection
+    // of plane and circle.  That is, are there *any* points on the plane that are within the bounds described?
+    if (isNumericallyIdentical(q)) {
+      //System.err.println(" Identical plane");
+      // The only way to efficiently figure this out will be to have a list of trial points available to evaluate.
+      // We look for any point that fulfills all the bounds.
+      for (GeoPoint p : notablePoints) {
+        if (meetsAllBounds(p, bounds, moreBounds)) {
+          //System.err.println("  found a notable point in bounds, so intersects");
+          return true;
+        }
+      }
+      for (GeoPoint p : moreNotablePoints) {
+        if (meetsAllBounds(p, bounds, moreBounds)) {
+          //System.err.println("  found a notable point in bounds, so intersects");
+          return true;
+        }
+      }
+      //System.err.println("  no notable points inside found; no intersection");
+      return false;
+    }
+    return findIntersections(planetModel, q, bounds, moreBounds).length > 0;
+  }
+
+  /**
+   * Returns true if this plane and the other plane are identical within the margin of error.
+   * @param p is the plane to compare against.
+   * @return true if the planes are numerically identical.
+   */
+  protected boolean isNumericallyIdentical(final Plane p) {
+    // We can get the correlation by just doing a parallel plane check.  If that passes, then compute a point on the plane
+    // (using D) and see if it also on the other plane.
+    if (Math.abs(this.y * p.z - this.z * p.y) >= MINIMUM_RESOLUTION)
+      return false;
+    if (Math.abs(this.z * p.x - this.x * p.z) >= MINIMUM_RESOLUTION)
+      return false;
+    if (Math.abs(this.x * p.y - this.y * p.x) >= MINIMUM_RESOLUTION)
+      return false;
+
+    // Now, see whether the parallel planes are in fact on top of one another.
+    // The math:
+    // We need a single point that fulfills:
+    // Ax + By + Cz + D = 0
+    // Pick:
+    // x0 = -(A * D) / (A^2 + B^2 + C^2)
+    // y0 = -(B * D) / (A^2 + B^2 + C^2)
+    // z0 = -(C * D) / (A^2 + B^2 + C^2)
+    // Check:
+    // A (x0) + B (y0) + C (z0) + D =? 0
+    // A (-(A * D) / (A^2 + B^2 + C^2)) + B (-(B * D) / (A^2 + B^2 + C^2)) + C (-(C * D) / (A^2 + B^2 + C^2)) + D ?= 0
+    // -D [ A^2 / (A^2 + B^2 + C^2) + B^2 / (A^2 + B^2 + C^2) + C^2 / (A^2 + B^2 + C^2)] + D ?= 0
+    // Yes.
+    final double denom = 1.0 / (p.x * p.x + p.y * p.y + p.z * p.z);
+    return evaluateIsZero(-p.x * p.D * denom, -p.y * p.D * denom, -p.z * p.D * denom);
+  }
+
+  /**
+   * Check if a vector meets the provided bounds.
+   * @param p is the vector.
+   * @param bounds are the bounds.
+   * @return true if the vector describes a point within the bounds.
+   */
+  protected static boolean meetsAllBounds(final Vector p, final Membership[] bounds) {
+    return meetsAllBounds(p.x, p.y, p.z, bounds);
+  }
+
+  /**
+   * Check if a vector meets the provided bounds.
+   * @param x is the x value.
+   * @param y is the y value.
+   * @param z is the z value.
+   * @param bounds are the bounds.
+   * @return true if the vector describes a point within the bounds.
+   */
+  protected static boolean meetsAllBounds(final double x, final double y, final double z, final Membership[] bounds) {
+    for (final Membership bound : bounds) {
+      if (!bound.isWithin(x,y,z))
+        return false;
+    }
+    return true;
+  }
+
+  /**
+   * Check if a vector meets the provided bounds.
+   * @param p is the vector.
+   * @param bounds are the bounds.
+   * @param moreBounds are an additional set of bounds.
+   * @return true if the vector describes a point within the bounds.
+   */
+  protected static boolean meetsAllBounds(final Vector p, final Membership[] bounds, final Membership[] moreBounds) {
+    return meetsAllBounds(p.x, p.y, p.z, bounds, moreBounds);
+  }
+
+  /**
+   * Check if a vector meets the provided bounds.
+   * @param x is the x value.
+   * @param y is the y value.
+   * @param z is the z value.
+   * @param bounds are the bounds.
+   * @param moreBounds are an additional set of bounds.
+   * @return true if the vector describes a point within the bounds.
+   */
+  protected static boolean meetsAllBounds(final double x, final double y, final double z, final Membership[] bounds,
+                                          final Membership[] moreBounds) {
+    return meetsAllBounds(x,y,z, bounds) && meetsAllBounds(x,y,z, moreBounds);
+  }
+
+  /**
+   * Find a sample point on the intersection between two planes and the world.
+   * @param planetModel is the planet model.
+   * @param q is the second plane to consider.
+   * @return a sample point that is on the intersection between the two planes and the world.
+   */
+  public GeoPoint getSampleIntersectionPoint(final PlanetModel planetModel, final Plane q) {
+    final GeoPoint[] intersections = findIntersections(planetModel, q, NO_BOUNDS, NO_BOUNDS);
+    if (intersections.length == 0)
+      return null;
+    return intersections[0];
+  }
+
+  @Override
+  public String toString() {
+    return "[A=" + x + ", B=" + y + "; C=" + z + "; D=" + D + "]";
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!super.equals(o))
+      return false;
+    if (!(o instanceof Plane))
+      return false;
+    Plane other = (Plane) o;
+    return other.D == D;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    long temp;
+    temp = Double.doubleToLongBits(D);
+    result = 31 * result + (int) (temp ^ (temp >>> 32));
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/PlanetModel.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/PlanetModel.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/PlanetModel.java
new file mode 100644
index 0000000..d45d776
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/PlanetModel.java
@@ -0,0 +1,277 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Holds mathematical constants associated with the model of a planet.
+ * @lucene.experimental
+ */
+public class PlanetModel {
+  
+  /** Planet model corresponding to sphere. */
+  public static final PlanetModel SPHERE = new PlanetModel(1.0,1.0);
+
+  /** Mean radius */
+  public static final double WGS84_MEAN = 6371009.0;
+  /** Polar radius */
+  public static final double WGS84_POLAR = 6356752.314245;
+  /** Equatorial radius */
+  public static final double WGS84_EQUATORIAL = 6378137.0;
+  /** Planet model corresponding to WGS84 */
+  public static final PlanetModel WGS84 = new PlanetModel(WGS84_EQUATORIAL/WGS84_MEAN,
+    WGS84_POLAR/WGS84_MEAN);
+
+  // Surface of the planet:
+  // x^2/a^2 + y^2/b^2 + z^2/c^2 = 1.0
+  // Scaling factors are a,b,c.  geo3d can only support models where a==b, so use ab instead.
+  
+  /** The x/y scaling factor */
+  public final double ab;
+  /** The z scaling factor */
+  public final double c;
+  /** The inverse of ab */
+  public final double inverseAb;
+  /** The inverse of c */
+  public final double inverseC;
+  /** The square of the inverse of ab */
+  public final double inverseAbSquared;
+  /** The square of the inverse of c */
+  public final double inverseCSquared;
+  /** The flattening value */
+  public final double flattening;
+  /** The square ratio */
+  public final double squareRatio;
+  
+  // We do NOT include radius, because all computations in geo3d are in radians, not meters.
+  
+  // Compute north and south pole for planet model, since these are commonly used.
+  
+  /** North pole */
+  public final GeoPoint NORTH_POLE;
+  /** South pole */
+  public final GeoPoint SOUTH_POLE;
+  /** Min X pole */
+  public final GeoPoint MIN_X_POLE;
+  /** Max X pole */
+  public final GeoPoint MAX_X_POLE;
+  /** Min Y pole */
+  public final GeoPoint MIN_Y_POLE;
+  /** Max Y pole */
+  public final GeoPoint MAX_Y_POLE;
+  
+  /** Constructor.
+   * @param ab is the x/y scaling factor.
+   * @param c is the z scaling factor.
+   */
+  public PlanetModel(final double ab, final double c) {
+    this.ab = ab;
+    this.c = c;
+    this.inverseAb = 1.0 / ab;
+    this.inverseC = 1.0 / c;
+    this.flattening = (ab - c) * inverseAb;
+    this.squareRatio = (ab * ab - c * c) / (c * c);
+    this.inverseAbSquared = inverseAb * inverseAb;
+    this.inverseCSquared = inverseC * inverseC;
+    this.NORTH_POLE = new GeoPoint(c, 0.0, 0.0, 1.0, Math.PI * 0.5, 0.0);
+    this.SOUTH_POLE = new GeoPoint(c, 0.0, 0.0, -1.0, -Math.PI * 0.5, 0.0);
+    this.MIN_X_POLE = new GeoPoint(ab, -1.0, 0.0, 0.0, 0.0, -Math.PI);
+    this.MAX_X_POLE = new GeoPoint(ab, 1.0, 0.0, 0.0, 0.0, 0.0);
+    this.MIN_Y_POLE = new GeoPoint(ab, 0.0, -1.0, 0.0, 0.0, -Math.PI * 0.5);
+    this.MAX_Y_POLE = new GeoPoint(ab, 0.0, 1.0, 0.0, 0.0, Math.PI * 0.5);
+  }
+  
+  /** Find the minimum magnitude of all points on the ellipsoid.
+   * @return the minimum magnitude for the planet.
+   */
+  public double getMinimumMagnitude() {
+    return Math.min(this.ab, this.c);
+  }
+
+  /** Find the maximum magnitude of all points on the ellipsoid.
+   * @return the maximum magnitude for the planet.
+   */
+  public double getMaximumMagnitude() {
+    return Math.max(this.ab, this.c);
+  }
+  
+  /** Find the minimum x value.
+   *@return the minimum X value.
+   */
+  public double getMinimumXValue() {
+    return -this.ab;
+  }
+  
+  /** Find the maximum x value.
+   *@return the maximum X value.
+   */
+  public double getMaximumXValue() {
+    return this.ab;
+  }
+
+  /** Find the minimum y value.
+   *@return the minimum Y value.
+   */
+  public double getMinimumYValue() {
+    return -this.ab;
+  }
+  
+  /** Find the maximum y value.
+   *@return the maximum Y value.
+   */
+  public double getMaximumYValue() {
+    return this.ab;
+  }
+  
+  /** Find the minimum z value.
+   *@return the minimum Z value.
+   */
+  public double getMinimumZValue() {
+    return -this.c;
+  }
+  
+  /** Find the maximum z value.
+   *@return the maximum Z value.
+   */
+  public double getMaximumZValue() {
+    return this.c;
+  }
+
+  /** Check if point is on surface.
+   * @param v is the point to check.
+   * @return true if the point is on the planet surface.
+   */
+  public boolean pointOnSurface(final Vector v) {
+    return pointOnSurface(v.x, v.y, v.z);
+  }
+  
+  /** Check if point is on surface.
+   * @param x is the x coord.
+   * @param y is the y coord.
+   * @param z is the z coord.
+   */
+  public boolean pointOnSurface(final double x, final double y, final double z) {
+    // Equation of planet surface is:
+    // x^2 / a^2 + y^2 / b^2 + z^2 / c^2 - 1 = 0
+    return Math.abs(x * x * inverseAb * inverseAb + y * y * inverseAb * inverseAb + z * z * inverseC * inverseC - 1.0) < Vector.MINIMUM_RESOLUTION;
+  }
+
+  /** Check if point is outside surface.
+   * @param v is the point to check.
+   * @return true if the point is outside the planet surface.
+   */
+  public boolean pointOutside(final Vector v) {
+    return pointOutside(v.x, v.y, v.z);
+  }
+  
+  /** Check if point is outside surface.
+   * @param x is the x coord.
+   * @param y is the y coord.
+   * @param z is the z coord.
+   */
+  public boolean pointOutside(final double x, final double y, final double z) {
+    // Equation of planet surface is:
+    // x^2 / a^2 + y^2 / b^2 + z^2 / c^2 - 1 = 0
+    return (x * x + y * y) * inverseAb * inverseAb + z * z * inverseC * inverseC - 1.0 > Vector.MINIMUM_RESOLUTION;
+  }
+  
+  /** Compute surface distance between two points.
+   * @param p1 is the first point.
+   * @param p2 is the second point.
+   * @return the adjusted angle, when multiplied by the mean earth radius, yields a surface distance.  This will differ
+   * from GeoPoint.arcDistance() only when the planet model is not a sphere. @see {@link GeoPoint#arcDistance(GeoPoint)}
+   */
+  public double surfaceDistance(final GeoPoint p1, final GeoPoint p2) {
+    final double latA = p1.getLatitude();
+    final double lonA = p1.getLongitude();
+    final double latB = p2.getLatitude();
+    final double lonB = p2.getLongitude();
+
+    final double L = lonB - lonA;
+    final double oF = 1.0 - this.flattening;
+    final double U1 = Math.atan(oF * Math.tan(latA));
+    final double U2 = Math.atan(oF * Math.tan(latB));
+    final double sU1 = Math.sin(U1);
+    final double cU1 = Math.cos(U1);
+    final double sU2 = Math.sin(U2);
+    final double cU2 = Math.cos(U2);
+
+    double sigma, sinSigma, cosSigma;
+    double cos2Alpha, cos2SigmaM;
+    
+    double lambda = L;
+    double iters = 100;
+
+    do {
+      final double sinLambda = Math.sin(lambda);
+      final double cosLambda = Math.cos(lambda);
+      sinSigma = Math.sqrt((cU2 * sinLambda) * (cU2 * sinLambda) + (cU1 * sU2 - sU1 * cU2 * cosLambda)
+          * (cU1 * sU2 - sU1 * cU2 * cosLambda));
+      if (Math.abs(sinSigma) < Vector.MINIMUM_RESOLUTION)
+        return 0.0;
+
+      cosSigma = sU1 * sU2 + cU1 * cU2 * cosLambda;
+      sigma = Math.atan2(sinSigma, cosSigma);
+      final double sinAlpha = cU1 * cU2 * sinLambda / sinSigma;
+      cos2Alpha = 1.0 - sinAlpha * sinAlpha;
+      cos2SigmaM = cosSigma - 2.0 * sU1 * sU2 / cos2Alpha;
+
+      final double c = this.flattening * 0.625 * cos2Alpha * (4.0 + this.flattening * (4.0 - 3.0 * cos2Alpha));
+      final double lambdaP = lambda;
+      lambda = L + (1.0 - c) * this.flattening * sinAlpha * (sigma + c * sinSigma * (cos2SigmaM + c * cosSigma *
+          (-1.0 + 2.0 * cos2SigmaM * cos2SigmaM)));
+      if (Math.abs(lambda - lambdaP) < Vector.MINIMUM_RESOLUTION)
+        break;
+    } while (--iters > 0);
+
+    if (iters == 0)
+      return 0.0;
+
+    final double uSq = cos2Alpha * this.squareRatio;
+    final double A = 1.0 + uSq * 0.00006103515625 * (4096.0 + uSq * (-768.0 + uSq * (320.0 - 175.0 * uSq)));
+    final double B = uSq * 0.0009765625 * (256.0 + uSq * (-128.0 + uSq * (74.0 - 47.0 * uSq)));
+    final double deltaSigma = B * sinSigma * (cos2SigmaM + B * 0.25 * (cosSigma * (-1.0 + 2.0 * cos2SigmaM * cos2SigmaM) - B * 0.16666666666666666666667 * cos2SigmaM
+            * (-3.0 + 4.0 * sinSigma * sinSigma) * (-3.0 + 4.0 * cos2SigmaM * cos2SigmaM)));
+
+    return this.c * A * (sigma - deltaSigma);
+  }
+
+  @Override
+  public boolean equals(final Object o) {
+    if (!(o instanceof PlanetModel))
+      return false;
+    final PlanetModel other = (PlanetModel)o;
+    return ab == other.ab && c == other.c;
+  }
+  
+  @Override
+  public int hashCode() {
+    return Double.hashCode(ab) + Double.hashCode(c);
+  }
+  
+  @Override
+  public String toString() {
+    if (this.equals(SPHERE)) {
+      return "PlanetModel.SPHERE";
+    } else if (this.equals(WGS84)) {
+      return "PlanetModel.WGS84";
+    } else {
+      return "PlanetModel(ab="+ab+" c="+c+")";
+    }
+  }
+}
+
+


[28/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 3a31a8c)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/LinearDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/LinearDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/LinearDistance.java
deleted file mode 100644
index 9cbedba..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/LinearDistance.java
+++ /dev/null
@@ -1,56 +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.geo3d;
-
-/**
- * Linear distance computation style.
- *
- * @lucene.experimental
- */
-public class LinearDistance implements DistanceStyle {
-  
-  /** A convenient instance */
-  public final static LinearDistance INSTANCE = new LinearDistance();
-  
-  /** Constructor.
-   */
-  public LinearDistance() {
-  }
-  
-  @Override
-  public double computeDistance(final GeoPoint point1, final GeoPoint point2) {
-    return point1.linearDistance(point2);
-  }
-  
-  @Override
-  public double computeDistance(final GeoPoint point1, final double x2, final double y2, final double z2) {
-    return point1.linearDistance(x2,y2,z2);
-  }
-
-  @Override
-  public double computeDistance(final PlanetModel planetModel, final Plane plane, final GeoPoint point, final Membership... bounds) {
-    return plane.linearDistance(planetModel, point, bounds);
-  }
-  
-  @Override
-  public double computeDistance(final PlanetModel planetModel, final Plane plane, final double x, final double y, final double z, final Membership... bounds) {
-    return plane.linearDistance(planetModel, x,y,z, bounds);
-  }
-
-}
-
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/LinearSquaredDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/LinearSquaredDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/LinearSquaredDistance.java
deleted file mode 100644
index 028d3c4..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/LinearSquaredDistance.java
+++ /dev/null
@@ -1,56 +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.geo3d;
-
-/**
- * Linear squared distance computation style.
- *
- * @lucene.experimental
- */
-public class LinearSquaredDistance implements DistanceStyle {
-  
-  /** A convenient instance */
-  public final static LinearSquaredDistance INSTANCE = new LinearSquaredDistance();
-  
-  /** Constructor.
-   */
-  public LinearSquaredDistance() {
-  }
-  
-  @Override
-  public double computeDistance(final GeoPoint point1, final GeoPoint point2) {
-    return point1.linearDistanceSquared(point2);
-  }
-  
-  @Override
-  public double computeDistance(final GeoPoint point1, final double x2, final double y2, final double z2) {
-    return point1.linearDistanceSquared(x2,y2,z2);
-  }
-
-  @Override
-  public double computeDistance(final PlanetModel planetModel, final Plane plane, final GeoPoint point, final Membership... bounds) {
-    return plane.linearDistanceSquared(planetModel, point, bounds);
-  }
-  
-  @Override
-  public double computeDistance(final PlanetModel planetModel, final Plane plane, final double x, final double y, final double z, final Membership... bounds) {
-    return plane.linearDistanceSquared(planetModel, x,y,z, bounds);
-  }
-
-}
-
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Membership.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Membership.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Membership.java
deleted file mode 100755
index 3ca6b09..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Membership.java
+++ /dev/null
@@ -1,46 +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.geo3d;
-
-/**
- * Implemented by Geo3D shapes that can calculate if a point is within it or not.
- *
- * @lucene.experimental
- */
-public interface Membership {
-
-  /**
-   * Check if a point is within this shape.
-   *
-   * @param point is the point to check.
-   * @return true if the point is within this shape
-   */
-  public default boolean isWithin(final Vector point) {
-    return isWithin(point.x, point.y, point.z);
-  }
-
-  /**
-   * Check if a point is within this shape.
-   *
-   * @param x is x coordinate of point to check.
-   * @param y is y coordinate of point to check.
-   * @param z is z coordinate of point to check.
-   * @return true if the point is within this shape
-   */
-  public boolean isWithin(final double x, final double y, final double z);
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/NormalDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/NormalDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/NormalDistance.java
deleted file mode 100644
index cdac0d2..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/NormalDistance.java
+++ /dev/null
@@ -1,56 +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.geo3d;
-
-/**
- * Normal distance computation style.
- *
- * @lucene.experimental
- */
-public class NormalDistance implements DistanceStyle {
-  
-  /** A convenient instance */
-  public final static NormalDistance INSTANCE = new NormalDistance();
-  
-  /** Constructor.
-   */
-  public NormalDistance() {
-  }
-  
-  @Override
-  public double computeDistance(final GeoPoint point1, final GeoPoint point2) {
-    return point1.normalDistance(point2);
-  }
-  
-  @Override
-  public double computeDistance(final GeoPoint point1, final double x2, final double y2, final double z2) {
-    return point1.normalDistance(x2,y2,z2);
-  }
-
-  @Override
-  public double computeDistance(final PlanetModel planetModel, final Plane plane, final GeoPoint point, final Membership... bounds) {
-    return plane.normalDistance(point, bounds);
-  }
-  
-  @Override
-  public double computeDistance(final PlanetModel planetModel, final Plane plane, final double x, final double y, final double z, final Membership... bounds) {
-    return plane.normalDistance(x,y,z, bounds);
-  }
-
-}
-
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/NormalSquaredDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/NormalSquaredDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/NormalSquaredDistance.java
deleted file mode 100644
index 035fd40..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/NormalSquaredDistance.java
+++ /dev/null
@@ -1,56 +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.geo3d;
-
-/**
- * Normal squared distance computation style.
- *
- * @lucene.experimental
- */
-public class NormalSquaredDistance implements DistanceStyle {
-  
-  /** A convenient instance */
-  public final static NormalSquaredDistance INSTANCE = new NormalSquaredDistance();
-  
-  /** Constructor.
-   */
-  public NormalSquaredDistance() {
-  }
-  
-  @Override
-  public double computeDistance(final GeoPoint point1, final GeoPoint point2) {
-    return point1.normalDistanceSquared(point2);
-  }
-  
-  @Override
-  public double computeDistance(final GeoPoint point1, final double x2, final double y2, final double z2) {
-    return point1.normalDistanceSquared(x2,y2,z2);
-  }
-
-  @Override
-  public double computeDistance(final PlanetModel planetModel, final Plane plane, final GeoPoint point, final Membership... bounds) {
-    return plane.normalDistanceSquared(point, bounds);
-  }
-  
-  @Override
-  public double computeDistance(final PlanetModel planetModel, final Plane plane, final double x, final double y, final double z, final Membership... bounds) {
-    return plane.normalDistanceSquared(x,y,z, bounds);
-  }
-
-}
-
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0a1951be/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Plane.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Plane.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Plane.java
deleted file mode 100755
index 07d0c5b..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/Plane.java
+++ /dev/null
@@ -1,1657 +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.geo3d;
-
-/**
- * We know about three kinds of planes.  First kind: general plain through two points and origin
- * Second kind: horizontal plane at specified height.  Third kind: vertical plane with specified x and y value, through origin.
- *
- * @lucene.experimental
- */
-public class Plane extends Vector {
-  /** An array with no points in it */
-  protected final static GeoPoint[] NO_POINTS = new GeoPoint[0];
-  /** An array with no bounds in it */
-  protected final static Membership[] NO_BOUNDS = new Membership[0];
-  /** A vertical plane normal to the Y axis */
-  protected final static Plane normalYPlane = new Plane(0.0,1.0,0.0,0.0);
-  /** A vertical plane normal to the X axis */
-  protected final static Plane normalXPlane = new Plane(1.0,0.0,0.0,0.0);
-  /** A vertical plane normal to the Z axis */
-  protected final static Plane normalZPlane = new Plane(0.0,0.0,1.0,0.0);
-
-  /** Ax + By + Cz + D = 0 */
-  public final double D;
-
-  /**
-   * Construct a plane with all four coefficients defined.
-   *@param A is A
-   *@param B is B
-   *@param C is C
-   *@param D is D
-   */
-  public Plane(final double A, final double B, final double C, final double D) {
-    super(A, B, C);
-    this.D = D;
-  }
-
-  /**
-   * Construct a plane through two points and origin.
-   *
-   * @param A is the first point (origin based).
-   * @param B is the second point (origin based).
-   */
-  public Plane(final Vector A, final Vector B) {
-    super(A, B);
-    D = 0.0;
-  }
-
-  /**
-   * Construct a horizontal plane at a specified Z.
-   *
-   * @param planetModel is the planet model.
-   * @param sinLat is the sin(latitude).
-   */
-  public Plane(final PlanetModel planetModel, final double sinLat) {
-    super(0.0, 0.0, 1.0);
-    D = -sinLat * computeDesiredEllipsoidMagnitude(planetModel, sinLat);
-  }
-
-  /**
-   * Construct a vertical plane through a specified
-   * x, y and origin.
-   *
-   * @param x is the specified x value.
-   * @param y is the specified y value.
-   */
-  public Plane(final double x, final double y) {
-    super(y, -x, 0.0);
-    D = 0.0;
-  }
-
-  /**
-   * Construct a plane with a specific vector, and D offset
-   * from origin.
-   * @param v is the normal vector.
-   * @param D is the D offset from the origin.
-   */
-  public Plane(final Vector v, final double D) {
-    super(v.x, v.y, v.z);
-    this.D = D;
-  }
-
-  /** Construct the most accurate normalized plane through an x-y point and including the Z axis.
-   * If none of the points can determine the plane, return null.
-   * @param planePoints is a set of points to choose from.  The best one for constructing the most precise plane is picked.
-   * @return the plane
-   */
-  public static Plane constructNormalizedZPlane(final Vector... planePoints) {
-    // Pick the best one (with the greatest x-y distance)
-    double bestDistance = 0.0;
-    Vector bestPoint = null;
-    for (final Vector point : planePoints) {
-      final double pointDist = point.x * point.x + point.y * point.y;
-      if (pointDist > bestDistance) {
-        bestDistance = pointDist;
-        bestPoint = point;
-      }
-    }
-    return constructNormalizedZPlane(bestPoint.x, bestPoint.y);
-  }
-
-  /** Construct the most accurate normalized plane through an x-z point and including the Y axis.
-   * If none of the points can determine the plane, return null.
-   * @param planePoints is a set of points to choose from.  The best one for constructing the most precise plane is picked.
-   * @return the plane
-   */
-  public static Plane constructNormalizedYPlane(final Vector... planePoints) {
-    // Pick the best one (with the greatest x-z distance)
-    double bestDistance = 0.0;
-    Vector bestPoint = null;
-    for (final Vector point : planePoints) {
-      final double pointDist = point.x * point.x + point.z * point.z;
-      if (pointDist > bestDistance) {
-        bestDistance = pointDist;
-        bestPoint = point;
-      }
-    }
-    return constructNormalizedYPlane(bestPoint.x, bestPoint.z, 0.0);
-  }
-
-  /** Construct the most accurate normalized plane through an y-z point and including the X axis.
-   * If none of the points can determine the plane, return null.
-   * @param planePoints is a set of points to choose from.  The best one for constructing the most precise plane is picked.
-   * @return the plane
-   */
-  public static Plane constructNormalizedXPlane(final Vector... planePoints) {
-    // Pick the best one (with the greatest y-z distance)
-    double bestDistance = 0.0;
-    Vector bestPoint = null;
-    for (final Vector point : planePoints) {
-      final double pointDist = point.y * point.y + point.z * point.z;
-      if (pointDist > bestDistance) {
-        bestDistance = pointDist;
-        bestPoint = point;
-      }
-    }
-    return constructNormalizedXPlane(bestPoint.y, bestPoint.z, 0.0);
-  }
-
-  /** Construct a normalized plane through an x-y point and including the Z axis.
-   * If the x-y point is at (0,0), return null.
-   * @param x is the x value.
-   * @param y is the y value.
-   * @return a plane passing through the Z axis and (x,y,0).
-   */
-  public static Plane constructNormalizedZPlane(final double x, final double y) {
-    if (Math.abs(x) < MINIMUM_RESOLUTION && Math.abs(y) < MINIMUM_RESOLUTION)
-      return null;
-    final double denom = 1.0 / Math.sqrt(x*x + y*y);
-    return new Plane(y * denom, -x * denom, 0.0, 0.0);
-  }
-
-  /** Construct a normalized plane through an x-z point and parallel to the Y axis.
-   * If the x-z point is at (0,0), return null.
-   * @param x is the x value.
-   * @param z is the z value.
-   * @param DValue is the offset from the origin for the plane.
-   * @return a plane parallel to the Y axis and perpendicular to the x and z values given.
-   */
-  public static Plane constructNormalizedYPlane(final double x, final double z, final double DValue) {
-    if (Math.abs(x) < MINIMUM_RESOLUTION && Math.abs(z) < MINIMUM_RESOLUTION)
-      return null;
-    final double denom = 1.0 / Math.sqrt(x*x + z*z);
-    return new Plane(z * denom, 0.0, -x * denom, DValue);
-  }
-
-  /** Construct a normalized plane through a y-z point and parallel to the X axis.
-   * If the y-z point is at (0,0), return null.
-   * @param y is the y value.
-   * @param z is the z value.
-   * @param DValue is the offset from the origin for the plane.
-   * @return a plane parallel to the X axis and perpendicular to the y and z values given.
-   */
-  public static Plane constructNormalizedXPlane(final double y, final double z, final double DValue) {
-    if (Math.abs(y) < MINIMUM_RESOLUTION && Math.abs(z) < MINIMUM_RESOLUTION)
-      return null;
-    final double denom = 1.0 / Math.sqrt(y*y + z*z);
-    return new Plane(0.0, z * denom, -y * denom, DValue);
-  }
-  
-  /**
-   * Evaluate the plane equation for a given point, as represented
-   * by a vector.
-   *
-   * @param v is the vector.
-   * @return the result of the evaluation.
-   */
-  public double evaluate(final Vector v) {
-    return dotProduct(v) + D;
-  }
-
-  /**
-   * Evaluate the plane equation for a given point, as represented
-   * by a vector.
-   * @param x is the x value.
-   * @param y is the y value.
-   * @param z is the z value.
-   * @return the result of the evaluation.
-   */
-  public double evaluate(final double x, final double y, final double z) {
-    return dotProduct(x, y, z) + D;
-  }
-
-  /**
-   * Evaluate the plane equation for a given point, as represented
-   * by a vector.
-   *
-   * @param v is the vector.
-   * @return true if the result is on the plane.
-   */
-  public boolean evaluateIsZero(final Vector v) {
-    return Math.abs(evaluate(v)) < MINIMUM_RESOLUTION;
-  }
-
-  /**
-   * Evaluate the plane equation for a given point, as represented
-   * by a vector.
-   *
-   * @param x is the x value.
-   * @param y is the y value.
-   * @param z is the z value.
-   * @return true if the result is on the plane.
-   */
-  public boolean evaluateIsZero(final double x, final double y, final double z) {
-    return Math.abs(evaluate(x, y, z)) < MINIMUM_RESOLUTION;
-  }
-
-  /**
-   * Build a normalized plane, so that the vector is normalized.
-   *
-   * @return the normalized plane object, or null if the plane is indeterminate.
-   */
-  public Plane normalize() {
-    Vector normVect = super.normalize();
-    if (normVect == null)
-      return null;
-    return new Plane(normVect, this.D);
-  }
-
-  /** Compute arc distance from plane to a vector expressed with a {@link GeoPoint}.
-   *  @see #arcDistance(PlanetModel, double, double, double, Membership...) */
-  public double arcDistance(final PlanetModel planetModel, final GeoPoint v, final Membership... bounds) {
-    return arcDistance(planetModel, v.x, v.y, v.z, bounds);
-  }
-    
-  /**
-   * Compute arc distance from plane to a vector.
-   * @param planetModel is the planet model.
-   * @param x is the x vector value.
-   * @param y is the y vector value.
-   * @param z is the z vector value.
-   * @param bounds are the bounds which constrain the intersection point.
-   * @return the arc distance.
-   */
-  public double arcDistance(final PlanetModel planetModel, final double x, final double y, final double z, final Membership... bounds) {
-
-    if (evaluateIsZero(x,y,z)) {
-      if (meetsAllBounds(x,y,z, bounds))
-        return 0.0;
-      return Double.MAX_VALUE;
-    }
-    
-    // First, compute the perpendicular plane.
-    final Plane perpPlane = new Plane(this.y * z - this.z * y, this.z * x - this.x * z, this.x * y - this.y * x, 0.0);
-
-    // We need to compute the intersection of two planes on the geo surface: this one, and its perpendicular.
-    // Then, we need to choose which of the two points we want to compute the distance to.  We pick the
-    // shorter distance always.
-    
-    final GeoPoint[] intersectionPoints = findIntersections(planetModel, perpPlane);
-    
-    // For each point, compute a linear distance, and take the minimum of them
-    double minDistance = Double.MAX_VALUE;
-    
-    for (final GeoPoint intersectionPoint : intersectionPoints) {
-      if (meetsAllBounds(intersectionPoint, bounds)) {
-        final double theDistance = intersectionPoint.arcDistance(x,y,z);
-        if (theDistance < minDistance) {
-          minDistance = theDistance;
-        }
-      }
-    }
-    return minDistance;
-
-  }
-
-  /**
-   * Compute normal distance from plane to a vector.
-   * @param v is the vector.
-   * @param bounds are the bounds which constrain the intersection point.
-   * @return the normal distance.
-   */
-  public double normalDistance(final Vector v, final Membership... bounds) {
-    return normalDistance(v.x, v.y, v.z, bounds);
-  }
-    
-  /**
-   * Compute normal distance from plane to a vector.
-   * @param x is the vector x.
-   * @param y is the vector y.
-   * @param z is the vector z.
-   * @param bounds are the bounds which constrain the intersection point.
-   * @return the normal distance.
-   */
-  public double normalDistance(final double x, final double y, final double z, final Membership... bounds) {
-
-    final double dist = evaluate(x,y,z);
-    final double perpX = x - dist * this.x;
-    final double perpY = y - dist * this.y;
-    final double perpZ = z - dist * this.z;
-
-    if (!meetsAllBounds(perpX, perpY, perpZ, bounds)) {
-      return Double.MAX_VALUE;
-    }
-    
-    return Math.abs(dist);
-  }
-  
-  /**
-   * Compute normal distance squared from plane to a vector.
-   * @param v is the vector.
-   * @param bounds are the bounds which constrain the intersection point.
-   * @return the normal distance squared.
-   */
-  public double normalDistanceSquared(final Vector v, final Membership... bounds) {
-    return normalDistanceSquared(v.x, v.y, v.z, bounds);
-  }
-  
-  /**
-   * Compute normal distance squared from plane to a vector.
-   * @param x is the vector x.
-   * @param y is the vector y.
-   * @param z is the vector z.
-   * @param bounds are the bounds which constrain the intersection point.
-   * @return the normal distance squared.
-   */
-  public double normalDistanceSquared(final double x, final double y, final double z, final Membership... bounds) {
-    final double normal = normalDistance(x,y,z,bounds);
-    if (normal == Double.MAX_VALUE)
-      return normal;
-    return normal * normal;
-  }
-
-  /**
-   * Compute linear distance from plane to a vector.  This is defined
-   * as the distance from the given point to the nearest intersection of 
-   * this plane with the planet surface.
-   * @param planetModel is the planet model.
-   * @param v is the point.
-   * @param bounds are the bounds which constrain the intersection point.
-   * @return the linear distance.
-   */
-  public double linearDistance(final PlanetModel planetModel, final GeoPoint v, final Membership... bounds) {
-    return linearDistance(planetModel, v.x, v.y, v.z, bounds);
-  }
-    
-  /**
-   * Compute linear distance from plane to a vector.  This is defined
-   * as the distance from the given point to the nearest intersection of 
-   * this plane with the planet surface.
-   * @param planetModel is the planet model.
-   * @param x is the vector x.
-   * @param y is the vector y.
-   * @param z is the vector z.
-   * @param bounds are the bounds which constrain the intersection point.
-   * @return the linear distance.
-   */
-  public double linearDistance(final PlanetModel planetModel, final double x, final double y, final double z, final Membership... bounds) {
-    if (evaluateIsZero(x,y,z)) {
-      if (meetsAllBounds(x,y,z, bounds))
-        return 0.0;
-      return Double.MAX_VALUE;
-    }
-    
-    // First, compute the perpendicular plane.
-    final Plane perpPlane = new Plane(this.y * z - this.z * y, this.z * x - this.x * z, this.x * y - this.y * x, 0.0);
-
-    // We need to compute the intersection of two planes on the geo surface: this one, and its perpendicular.
-    // Then, we need to choose which of the two points we want to compute the distance to.  We pick the
-    // shorter distance always.
-    
-    final GeoPoint[] intersectionPoints = findIntersections(planetModel, perpPlane);
-    
-    // For each point, compute a linear distance, and take the minimum of them
-    double minDistance = Double.MAX_VALUE;
-    
-    for (final GeoPoint intersectionPoint : intersectionPoints) {
-      if (meetsAllBounds(intersectionPoint, bounds)) {
-        final double theDistance = intersectionPoint.linearDistance(x,y,z);
-        if (theDistance < minDistance) {
-          minDistance = theDistance;
-        }
-      }
-    }
-    return minDistance;
-  }
-      
-  /**
-   * Compute linear distance squared from plane to a vector.  This is defined
-   * as the distance from the given point to the nearest intersection of 
-   * this plane with the planet surface.
-   * @param planetModel is the planet model.
-   * @param v is the point.
-   * @param bounds are the bounds which constrain the intersection point.
-   * @return the linear distance squared.
-   */
-  public double linearDistanceSquared(final PlanetModel planetModel, final GeoPoint v, final Membership... bounds) {
-    return linearDistanceSquared(planetModel, v.x, v.y, v.z, bounds);
-  }
-  
-  /**
-   * Compute linear distance squared from plane to a vector.  This is defined
-   * as the distance from the given point to the nearest intersection of 
-   * this plane with the planet surface.
-   * @param planetModel is the planet model.
-   * @param x is the vector x.
-   * @param y is the vector y.
-   * @param z is the vector z.
-   * @param bounds are the bounds which constrain the intersection point.
-   * @return the linear distance squared.
-   */
-  public double linearDistanceSquared(final PlanetModel planetModel, final double x, final double y, final double z, final Membership... bounds) {
-    final double linearDistance = linearDistance(planetModel, x, y, z, bounds);
-    return linearDistance * linearDistance;
-  }
-
-  /**
-   * Find points on the boundary of the intersection of a plane and the unit sphere,
-   * given a starting point, and ending point, and a list of proportions of the arc (e.g. 0.25, 0.5, 0.75).
-   * The angle between the starting point and ending point is assumed to be less than pi.
-   * @param start is the start point.
-   * @param end is the end point.
-   * @param proportions is an array of fractional proportions measured between start and end.
-   * @return an array of points corresponding to the proportions passed in.
-   */
-  public GeoPoint[] interpolate(final GeoPoint start, final GeoPoint end, final double[] proportions) {
-    // Steps:
-    // (1) Translate (x0,y0,z0) of endpoints into origin-centered place:
-    // x1 = x0 + D*A
-    // y1 = y0 + D*B
-    // z1 = z0 + D*C
-    // (2) Rotate counterclockwise in x-y:
-    // ra = -atan2(B,A)
-    // x2 = x1 cos ra - y1 sin ra
-    // y2 = x1 sin ra + y1 cos ra
-    // z2 = z1
-    // Faster:
-    // cos ra = A/sqrt(A^2+B^2+C^2)
-    // sin ra = -B/sqrt(A^2+B^2+C^2)
-    // cos (-ra) = A/sqrt(A^2+B^2+C^2)
-    // sin (-ra) = B/sqrt(A^2+B^2+C^2)
-    // (3) Rotate clockwise in x-z:
-    // ha = pi/2 - asin(C/sqrt(A^2+B^2+C^2))
-    // x3 = x2 cos ha - z2 sin ha
-    // y3 = y2
-    // z3 = x2 sin ha + z2 cos ha
-    // At this point, z3 should be zero.
-    // Faster:
-    // sin(ha) = cos(asin(C/sqrt(A^2+B^2+C^2))) = sqrt(1 - C^2/(A^2+B^2+C^2)) = sqrt(A^2+B^2)/sqrt(A^2+B^2+C^2)
-    // cos(ha) = sin(asin(C/sqrt(A^2+B^2+C^2))) = C/sqrt(A^2+B^2+C^2)
-    // (4) Compute interpolations by getting longitudes of original points
-    // la = atan2(y3,x3)
-    // (5) Rotate new points (xN0, yN0, zN0) counter-clockwise in x-z:
-    // ha = -(pi - asin(C/sqrt(A^2+B^2+C^2)))
-    // xN1 = xN0 cos ha - zN0 sin ha
-    // yN1 = yN0
-    // zN1 = xN0 sin ha + zN0 cos ha
-    // (6) Rotate new points clockwise in x-y:
-    // ra = atan2(B,A)
-    // xN2 = xN1 cos ra - yN1 sin ra
-    // yN2 = xN1 sin ra + yN1 cos ra
-    // zN2 = zN1
-    // (7) Translate new points:
-    // xN3 = xN2 - D*A
-    // yN3 = yN2 - D*B
-    // zN3 = zN2 - D*C
-
-    // First, calculate the angles and their sin/cos values
-    double A = x;
-    double B = y;
-    double C = z;
-
-    // Translation amounts
-    final double transX = -D * A;
-    final double transY = -D * B;
-    final double transZ = -D * C;
-
-    double cosRA;
-    double sinRA;
-    double cosHA;
-    double sinHA;
-
-    double magnitude = magnitude();
-    if (magnitude >= MINIMUM_RESOLUTION) {
-      final double denom = 1.0 / magnitude;
-      A *= denom;
-      B *= denom;
-      C *= denom;
-
-      // cos ra = A/sqrt(A^2+B^2+C^2)
-      // sin ra = -B/sqrt(A^2+B^2+C^2)
-      // cos (-ra) = A/sqrt(A^2+B^2+C^2)
-      // sin (-ra) = B/sqrt(A^2+B^2+C^2)
-      final double xyMagnitude = Math.sqrt(A * A + B * B);
-      if (xyMagnitude >= MINIMUM_RESOLUTION) {
-        final double xyDenom = 1.0 / xyMagnitude;
-        cosRA = A * xyDenom;
-        sinRA = -B * xyDenom;
-      } else {
-        cosRA = 1.0;
-        sinRA = 0.0;
-      }
-
-      // sin(ha) = cos(asin(C/sqrt(A^2+B^2+C^2))) = sqrt(1 - C^2/(A^2+B^2+C^2)) = sqrt(A^2+B^2)/sqrt(A^2+B^2+C^2)
-      // cos(ha) = sin(asin(C/sqrt(A^2+B^2+C^2))) = C/sqrt(A^2+B^2+C^2)
-      sinHA = xyMagnitude;
-      cosHA = C;
-    } else {
-      cosRA = 1.0;
-      sinRA = 0.0;
-      cosHA = 1.0;
-      sinHA = 0.0;
-    }
-
-    // Forward-translate the start and end points
-    final Vector modifiedStart = modify(start, transX, transY, transZ, sinRA, cosRA, sinHA, cosHA);
-    final Vector modifiedEnd = modify(end, transX, transY, transZ, sinRA, cosRA, sinHA, cosHA);
-    if (Math.abs(modifiedStart.z) >= MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("Start point was not on plane: " + modifiedStart.z);
-    if (Math.abs(modifiedEnd.z) >= MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("End point was not on plane: " + modifiedEnd.z);
-
-    // Compute the angular distance between start and end point
-    final double startAngle = Math.atan2(modifiedStart.y, modifiedStart.x);
-    final double endAngle = Math.atan2(modifiedEnd.y, modifiedEnd.x);
-
-    final double startMagnitude = Math.sqrt(modifiedStart.x * modifiedStart.x + modifiedStart.y * modifiedStart.y);
-    double delta;
-
-    double newEndAngle = endAngle;
-    while (newEndAngle < startAngle) {
-      newEndAngle += Math.PI * 2.0;
-    }
-
-    if (newEndAngle - startAngle <= Math.PI) {
-      delta = newEndAngle - startAngle;
-    } else {
-      double newStartAngle = startAngle;
-      while (newStartAngle < endAngle) {
-        newStartAngle += Math.PI * 2.0;
-      }
-      delta = newStartAngle - endAngle;
-    }
-
-    final GeoPoint[] returnValues = new GeoPoint[proportions.length];
-    for (int i = 0; i < returnValues.length; i++) {
-      final double newAngle = startAngle + proportions[i] * delta;
-      final double sinNewAngle = Math.sin(newAngle);
-      final double cosNewAngle = Math.cos(newAngle);
-      final Vector newVector = new Vector(cosNewAngle * startMagnitude, sinNewAngle * startMagnitude, 0.0);
-      returnValues[i] = reverseModify(newVector, transX, transY, transZ, sinRA, cosRA, sinHA, cosHA);
-    }
-
-    return returnValues;
-  }
-
-  /**
-   * Modify a point to produce a vector in translated/rotated space.
-   * @param start is the start point.
-   * @param transX is the translation x value.
-   * @param transY is the translation y value.
-   * @param transZ is the translation z value.
-   * @param sinRA is the sine of the ascension angle.
-   * @param cosRA is the cosine of the ascension angle.
-   * @param sinHA is the sine of the height angle.
-   * @param cosHA is the cosine of the height angle.
-   * @return the modified point.
-   */
-  protected static Vector modify(final GeoPoint start, final double transX, final double transY, final double transZ,
-                                 final double sinRA, final double cosRA, final double sinHA, final double cosHA) {
-    return start.translate(transX, transY, transZ).rotateXY(sinRA, cosRA).rotateXZ(sinHA, cosHA);
-  }
-
-  /**
-   * Reverse modify a point to produce a GeoPoint in normal space.
-   * @param point is the translated point.
-   * @param transX is the translation x value.
-   * @param transY is the translation y value.
-   * @param transZ is the translation z value.
-   * @param sinRA is the sine of the ascension angle.
-   * @param cosRA is the cosine of the ascension angle.
-   * @param sinHA is the sine of the height angle.
-   * @param cosHA is the cosine of the height angle.
-   * @return the original point.
-   */
-  protected static GeoPoint reverseModify(final Vector point, final double transX, final double transY, final double transZ,
-                                          final double sinRA, final double cosRA, final double sinHA, final double cosHA) {
-    final Vector result = point.rotateXZ(-sinHA, cosHA).rotateXY(-sinRA, cosRA).translate(-transX, -transY, -transZ);
-    return new GeoPoint(result.x, result.y, result.z);
-  }
-
-  /**
-   * Public version of findIntersections.
-   * @param planetModel is the planet model.
-   * @param q is the plane to intersect with.
-   * @param bounds are the bounds to consider to determine legal intersection points.
-   * @return the set of legal intersection points.
-   */
-  public GeoPoint[] findIntersections(final PlanetModel planetModel, final Plane q, final Membership... bounds) {
-    if (isNumericallyIdentical(q)) {
-      return null;
-    }
-    return findIntersections(planetModel, q, bounds, NO_BOUNDS);
-  }
-  
-  /**
-   * Find the intersection points between two planes, given a set of bounds.
-   *
-   * @param planetModel is the planet model to use in finding points.
-   * @param q          is the plane to intersect with.
-   * @param bounds     is the set of bounds.
-   * @param moreBounds is another set of bounds.
-   * @return the intersection point(s) on the unit sphere, if there are any.
-   */
-  protected GeoPoint[] findIntersections(final PlanetModel planetModel, final Plane q, final Membership[] bounds, final Membership[] moreBounds) {
-    //System.err.println("Looking for intersection between plane "+this+" and plane "+q+" within bounds");
-    // Unnormalized, unchecked...
-    final Vector lineVector = new Vector(y * q.z - z * q.y, z * q.x - x * q.z, x * q.y - y * q.x);
-    if (Math.abs(lineVector.x) < MINIMUM_RESOLUTION && Math.abs(lineVector.y) < MINIMUM_RESOLUTION && Math.abs(lineVector.z) < MINIMUM_RESOLUTION) {
-      // Degenerate case: parallel planes
-      //System.err.println(" planes are parallel - no intersection");
-      return NO_POINTS;
-    }
-
-    // The line will have the equation: A t + A0 = x, B t + B0 = y, C t + C0 = z.
-    // We have A, B, and C.  In order to come up with A0, B0, and C0, we need to find a point that is on both planes.
-    // To do this, we find the largest vector value (either x, y, or z), and look for a point that solves both plane equations
-    // simultaneous.  For example, let's say that the vector is (0.5,0.5,1), and the two plane equations are:
-    // 0.7 x + 0.3 y + 0.1 z + 0.0 = 0
-    // and
-    // 0.9 x - 0.1 y + 0.2 z + 4.0 = 0
-    // Then we'd pick z = 0, so the equations to solve for x and y would be:
-    // 0.7 x + 0.3y = 0.0
-    // 0.9 x - 0.1y = -4.0
-    // ... which can readily be solved using standard linear algebra.  Generally:
-    // Q0 x + R0 y = S0
-    // Q1 x + R1 y = S1
-    // ... can be solved by Cramer's rule:
-    // x = det(S0 R0 / S1 R1) / det(Q0 R0 / Q1 R1)
-    // y = det(Q0 S0 / Q1 S1) / det(Q0 R0 / Q1 R1)
-    // ... where det( a b / c d ) = ad - bc, so:
-    // x = (S0 * R1 - R0 * S1) / (Q0 * R1 - R0 * Q1)
-    // y = (Q0 * S1 - S0 * Q1) / (Q0 * R1 - R0 * Q1)
-    double x0;
-    double y0;
-    double z0;
-    // We try to maximize the determinant in the denominator
-    final double denomYZ = this.y * q.z - this.z * q.y;
-    final double denomXZ = this.x * q.z - this.z * q.x;
-    final double denomXY = this.x * q.y - this.y * q.x;
-    if (Math.abs(denomYZ) >= Math.abs(denomXZ) && Math.abs(denomYZ) >= Math.abs(denomXY)) {
-      // X is the biggest, so our point will have x0 = 0.0
-      if (Math.abs(denomYZ) < MINIMUM_RESOLUTION_SQUARED) {
-        //System.err.println(" Denominator is zero: no intersection");
-        return NO_POINTS;
-      }
-      final double denom = 1.0 / denomYZ;
-      x0 = 0.0;
-      y0 = (-this.D * q.z - this.z * -q.D) * denom;
-      z0 = (this.y * -q.D + this.D * q.y) * denom;
-    } else if (Math.abs(denomXZ) >= Math.abs(denomXY) && Math.abs(denomXZ) >= Math.abs(denomYZ)) {
-      // Y is the biggest, so y0 = 0.0
-      if (Math.abs(denomXZ) < MINIMUM_RESOLUTION_SQUARED) {
-        //System.err.println(" Denominator is zero: no intersection");
-        return NO_POINTS;
-      }
-      final double denom = 1.0 / denomXZ;
-      x0 = (-this.D * q.z - this.z * -q.D) * denom;
-      y0 = 0.0;
-      z0 = (this.x * -q.D + this.D * q.x) * denom;
-    } else {
-      // Z is the biggest, so Z0 = 0.0
-      if (Math.abs(denomXY) < MINIMUM_RESOLUTION_SQUARED) {
-        //System.err.println(" Denominator is zero: no intersection");
-        return NO_POINTS;
-      }
-      final double denom = 1.0 / denomXY;
-      x0 = (-this.D * q.y - this.y * -q.D) * denom;
-      y0 = (this.x * -q.D + this.D * q.x) * denom;
-      z0 = 0.0;
-    }
-
-    // Once an intersecting line is determined, the next step is to intersect that line with the ellipsoid, which
-    // will yield zero, one, or two points.
-    // The ellipsoid equation: 1,0 = x^2/a^2 + y^2/b^2 + z^2/c^2
-    // 1.0 = (At+A0)^2/a^2 + (Bt+B0)^2/b^2 + (Ct+C0)^2/c^2
-    // A^2 t^2 / a^2 + 2AA0t / a^2 + A0^2 / a^2 + B^2 t^2 / b^2 + 2BB0t / b^2 + B0^2 / b^2 + C^2 t^2 / c^2 + 2CC0t / c^2 + C0^2 / c^2  - 1,0 = 0.0
-    // [A^2 / a^2 + B^2 / b^2 + C^2 / c^2] t^2 + [2AA0 / a^2 + 2BB0 / b^2 + 2CC0 / c^2] t + [A0^2 / a^2 + B0^2 / b^2 + C0^2 / c^2 - 1,0] = 0.0
-    // Use the quadratic formula to determine t values and candidate point(s)
-    final double A = lineVector.x * lineVector.x * planetModel.inverseAbSquared +
-      lineVector.y * lineVector.y * planetModel.inverseAbSquared +
-      lineVector.z * lineVector.z * planetModel.inverseCSquared;
-    final double B = 2.0 * (lineVector.x * x0 * planetModel.inverseAbSquared + lineVector.y * y0 * planetModel.inverseAbSquared + lineVector.z * z0 * planetModel.inverseCSquared);
-    final double C = x0 * x0 * planetModel.inverseAbSquared + y0 * y0 * planetModel.inverseAbSquared + z0 * z0 * planetModel.inverseCSquared - 1.0;
-
-    final double BsquaredMinus = B * B - 4.0 * A * C;
-    if (Math.abs(BsquaredMinus) < MINIMUM_RESOLUTION_SQUARED) {
-      //System.err.println(" One point of intersection");
-      final double inverse2A = 1.0 / (2.0 * A);
-      // One solution only
-      final double t = -B * inverse2A;
-      GeoPoint point = new GeoPoint(lineVector.x * t + x0, lineVector.y * t + y0, lineVector.z * t + z0);
-      //System.err.println("  point: "+point);
-      //verifyPoint(planetModel, point, q);
-      if (point.isWithin(bounds, moreBounds))
-        return new GeoPoint[]{point};
-      return NO_POINTS;
-    } else if (BsquaredMinus > 0.0) {
-      //System.err.println(" Two points of intersection");
-      final double inverse2A = 1.0 / (2.0 * A);
-      // Two solutions
-      final double sqrtTerm = Math.sqrt(BsquaredMinus);
-      final double t1 = (-B + sqrtTerm) * inverse2A;
-      final double t2 = (-B - sqrtTerm) * inverse2A;
-      GeoPoint point1 = new GeoPoint(lineVector.x * t1 + x0, lineVector.y * t1 + y0, lineVector.z * t1 + z0);
-      GeoPoint point2 = new GeoPoint(lineVector.x * t2 + x0, lineVector.y * t2 + y0, lineVector.z * t2 + z0);
-      //verifyPoint(planetModel, point1, q);
-      //verifyPoint(planetModel, point2, q);
-      //System.err.println("  "+point1+" and "+point2);
-      if (point1.isWithin(bounds, moreBounds)) {
-        if (point2.isWithin(bounds, moreBounds))
-          return new GeoPoint[]{point1, point2};
-        return new GeoPoint[]{point1};
-      }
-      if (point2.isWithin(bounds, moreBounds))
-        return new GeoPoint[]{point2};
-      return NO_POINTS;
-    } else {
-      //System.err.println(" no solutions - no intersection");
-      return NO_POINTS;
-    }
-  }
-
-  /*
-  protected void verifyPoint(final PlanetModel planetModel, final GeoPoint point, final Plane q) {
-    if (!evaluateIsZero(point))
-      throw new RuntimeException("Intersection point not on original plane; point="+point+", plane="+this);
-    if (!q.evaluateIsZero(point))
-      throw new RuntimeException("Intersection point not on intersected plane; point="+point+", plane="+q);
-    if (Math.abs(point.x * point.x * planetModel.inverseASquared + point.y * point.y * planetModel.inverseBSquared + point.z * point.z * planetModel.inverseCSquared - 1.0) >= MINIMUM_RESOLUTION) 
-      throw new RuntimeException("Intersection point not on ellipsoid; point="+point);
-  }
-  */
-
-  /**
-   * Accumulate (x,y,z) bounds information for this plane, intersected with the unit sphere.
-   * Updates min/max information, using max/min points found
-   * within the specified bounds.
-   *
-   * @param planetModel is the planet model to use in determining bounds.
-   * @param boundsInfo is the xyz info to update with additional bounding information.
-   * @param bounds     are the surfaces delineating what's inside the shape.
-   */
-  public void recordBounds(final PlanetModel planetModel, final XYZBounds boundsInfo, final Membership... bounds) {
-    // Basic plan is to do three intersections of the plane and the planet.
-    // For min/max x, we intersect a vertical plane such that y = 0.
-    // For min/max y, we intersect a vertical plane such that x = 0.
-    // For min/max z, we intersect a vertical plane that is chosen to go through the high point of the arc.
-    // For clarity, load local variables with good names
-    final double A = this.x;
-    final double B = this.y;
-    final double C = this.z;
-
-    // Do Z.  This can be done simply because it is symmetrical.
-    if (!boundsInfo.isSmallestMinZ(planetModel) || !boundsInfo.isLargestMaxZ(planetModel)) {
-      //System.err.println("    computing Z bound");
-      // Compute Z bounds for this arc
-      // With ellipsoids, we really have only one viable way to do this computation.
-      // Specifically, we compute an appropriate vertical plane, based on the current plane's x-y orientation, and
-      // then intersect it with this one and with the ellipsoid.  This gives us zero, one, or two points to use
-      // as bounds.
-      // There is one special case: horizontal circles.  These require TWO vertical planes: one for the x, and one for
-      // the y, and we use all four resulting points in the bounds computation.
-      if ((Math.abs(A) >= MINIMUM_RESOLUTION || Math.abs(B) >= MINIMUM_RESOLUTION)) {
-        // NOT a degenerate case
-        //System.err.println("    not degenerate");
-        final Plane normalizedZPlane = constructNormalizedZPlane(A,B);
-        final GeoPoint[] points = findIntersections(planetModel, normalizedZPlane, bounds, NO_BOUNDS);
-        for (final GeoPoint point : points) {
-          assert planetModel.pointOnSurface(point);
-          //System.err.println("      Point = "+point+"; this.evaluate(point)="+this.evaluate(point)+"; normalizedZPlane.evaluate(point)="+normalizedZPlane.evaluate(point));
-          addPoint(boundsInfo, bounds, point);
-        }
-      } else {
-        // Since a==b==0, any plane including the Z axis suffices.
-        //System.err.println("      Perpendicular to z");
-        final GeoPoint[] points = findIntersections(planetModel, normalYPlane, NO_BOUNDS, NO_BOUNDS);
-        boundsInfo.addZValue(points[0]);
-      }
-    }
-
-    // First, compute common subexpressions
-    final double k = 1.0 / ((x*x + y*y)*planetModel.ab*planetModel.ab + z*z*planetModel.c*planetModel.c);
-    final double abSquared = planetModel.ab * planetModel.ab;
-    final double cSquared = planetModel.c * planetModel.c;
-    final double ASquared = A * A;
-    final double BSquared = B * B;
-    final double CSquared = C * C;
-    
-    final double r = 2.0*D*k;
-    final double rSquared = r * r;
-    
-    if (!boundsInfo.isSmallestMinX(planetModel) || !boundsInfo.isLargestMaxX(planetModel)) {
-      // For min/max x, we need to use lagrange multipliers.
-      //
-      // For this, we need grad(F(x,y,z)) = (dF/dx, dF/dy, dF/dz).
-      //
-      // Minimize and maximize f(x,y,z) = x, with respect to g(x,y,z) = Ax + By + Cz - D and h(x,y,z) = x^2/ab^2 + y^2/ab^2 + z^2/c^2 - 1
-      //
-      // grad(f(x,y,z)) = (1,0,0)
-      // grad(g(x,y,z)) = (A,B,C)
-      // grad(h(x,y,z)) = (2x/ab^2,2y/ab^2,2z/c^2)
-      //
-      // Equations we need to simultaneously solve:
-      // 
-      // grad(f(x,y,z)) = l * grad(g(x,y,z)) + m * grad(h(x,y,z))
-      // g(x,y,z) = 0
-      // h(x,y,z) = 0
-      // 
-      // Equations:
-      // 1 = l*A + m*2x/ab^2
-      // 0 = l*B + m*2y/ab^2
-      // 0 = l*C + m*2z/c^2
-      // Ax + By + Cz + D = 0
-      // x^2/ab^2 + y^2/ab^2 + z^2/c^2 - 1 = 0
-      // 
-      // Solve for x,y,z in terms of (l, m):
-      // 
-      // x = ((1 - l*A) * ab^2 ) / (2 * m)
-      // y = (-l*B * ab^2) / ( 2 * m)
-      // z = (-l*C * c^2)/ (2 * m)
-      // 
-      // Two equations, two unknowns:
-      // 
-      // A * (((1 - l*A) * ab^2 ) / (2 * m)) + B * ((-l*B * ab^2) / ( 2 * m)) + C * ((-l*C * c^2)/ (2 * m)) + D = 0
-      // 
-      // and
-      // 
-      // (((1 - l*A) * ab^2 ) / (2 * m))^2/ab^2 + ((-l*B * ab^2) / ( 2 * m))^2/ab^2 + ((-l*C * c^2)/ (2 * m))^2/c^2 - 1 = 0
-      // 
-      // Simple: solve for l and m, then find x from it.
-      // 
-      // (a) Use first equation to find l in terms of m.
-      // 
-      // A * (((1 - l*A) * ab^2 ) / (2 * m)) + B * ((-l*B * ab^2) / ( 2 * m)) + C * ((-l*C * c^2)/ (2 * m)) + D = 0
-      // A * ((1 - l*A) * ab^2 ) + B * (-l*B * ab^2) + C * (-l*C * c^2) + D * 2 * m = 0
-      // A * ab^2 - l*A^2* ab^2 - B^2 * l * ab^2 - C^2 * l * c^2 + D * 2 * m = 0
-      // - l *(A^2* ab^2 + B^2 * ab^2 + C^2 * c^2) + (A * ab^2 + D * 2 * m) = 0
-      // l = (A * ab^2 + D * 2 * m) / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
-      // l = A * ab^2 / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2) + m * 2 * D / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
-      // 
-      // For convenience:
-      // 
-      // k = 1.0 / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
-      // 
-      // Then:
-      // 
-      // l = A * ab^2 * k + m * 2 * D * k
-      // l = k * (A*ab^2 + m*2*D)
-      //
-      // For further convenience:
-      //
-      // q = A*ab^2*k
-      // r = 2*D*k
-      //
-      // l = (r*m + q)
-      // l^2 = (r^2 * m^2 + 2*r*m*q + q^2)
-      // 
-      // (b) Simplify the second equation before substitution
-      // 
-      // (((1 - l*A) * ab^2 ) / (2 * m))^2/ab^2 + ((-l*B * ab^2) / ( 2 * m))^2/ab^2 + ((-l*C * c^2)/ (2 * m))^2/c^2 - 1 = 0
-      // ((1 - l*A) * ab^2 )^2/ab^2 + (-l*B * ab^2)^2/ab^2 + (-l*C * c^2)^2/c^2 = 4 * m^2
-      // (1 - l*A)^2 * ab^2 + (-l*B)^2 * ab^2 + (-l*C)^2 * c^2 = 4 * m^2
-      // (1 - 2*l*A + l^2*A^2) * ab^2 + l^2*B^2 * ab^2 + l^2*C^2 * c^2 = 4 * m^2
-      // ab^2 - 2*A*ab^2*l + A^2*ab^2*l^2 + B^2*ab^2*l^2 + C^2*c^2*l^2 - 4*m^2 = 0
-      // 
-      // (c) Substitute for l, l^2
-      //
-      // ab^2 - 2*A*ab^2*(r*m + q) + A^2*ab^2*(r^2 * m^2 + 2*r*m*q + q^2) + B^2*ab^2*(r^2 * m^2 + 2*r*m*q + q^2) + C^2*c^2*(r^2 * m^2 + 2*r*m*q + q^2) - 4*m^2 = 0
-      // ab^2 - 2*A*ab^2*r*m - 2*A*ab^2*q + A^2*ab^2*r^2*m^2 + 2*A^2*ab^2*r*q*m +
-      //        A^2*ab^2*q^2 + B^2*ab^2*r^2*m^2 + 2*B^2*ab^2*r*q*m + B^2*ab^2*q^2 + C^2*c^2*r^2*m^2 + 2*C^2*c^2*r*q*m + C^2*c^2*q^2 - 4*m^2 = 0
-      //
-      // (d) Group
-      //
-      // m^2 * [A^2*ab^2*r^2 + B^2*ab^2*r^2 + C^2*c^2*r^2 - 4] +
-      // m * [- 2*A*ab^2*r + 2*A^2*ab^2*r*q + 2*B^2*ab^2*r*q + 2*C^2*c^2*r*q] +
-      // [ab^2 - 2*A*ab^2*q + A^2*ab^2*q^2 + B^2*ab^2*q^2 + C^2*c^2*q^2]  =  0
-      
-      //System.err.println("    computing X bound");
-      
-      // Useful subexpressions for this bound
-      final double q = A*abSquared*k;
-      final double qSquared = q * q;
-
-      // Quadratic equation
-      final double a = ASquared*abSquared*rSquared + BSquared*abSquared*rSquared + CSquared*cSquared*rSquared - 4.0;
-      final double b = - 2.0*A*abSquared*r + 2.0*ASquared*abSquared*r*q + 2.0*BSquared*abSquared*r*q + 2.0*CSquared*cSquared*r*q;
-      final double c = abSquared - 2.0*A*abSquared*q + ASquared*abSquared*qSquared + BSquared*abSquared*qSquared + CSquared*cSquared*qSquared;
-      
-      if (Math.abs(a) >= MINIMUM_RESOLUTION_SQUARED) {
-        final double sqrtTerm = b*b - 4.0*a*c;
-        if (Math.abs(sqrtTerm) < MINIMUM_RESOLUTION_SQUARED) {
-          // One solution
-          final double m = -b / (2.0 * a);
-          final double l = r * m + q;
-          // x = ((1 - l*A) * ab^2 ) / (2 * m)
-          // y = (-l*B * ab^2) / ( 2 * m)
-          // z = (-l*C * c^2)/ (2 * m)
-          final double denom0 = 0.5 / m;
-          final GeoPoint thePoint = new GeoPoint((1.0-l*A) * abSquared * denom0, -l*B * abSquared * denom0, -l*C * cSquared * denom0);
-          //Math is not quite accurate enough for this
-          //assert planetModel.pointOnSurface(thePoint): "Point: "+thePoint+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
-          //  (thePoint.x*thePoint.x*planetModel.inverseAb*planetModel.inverseAb + thePoint.y*thePoint.y*planetModel.inverseAb*planetModel.inverseAb + thePoint.z*thePoint.z*planetModel.inverseC*planetModel.inverseC);
-          //assert evaluateIsZero(thePoint): "Evaluation of point: "+evaluate(thePoint);
-          addPoint(boundsInfo, bounds, thePoint);
-        } else if (sqrtTerm > 0.0) {
-          // Two solutions
-          final double sqrtResult = Math.sqrt(sqrtTerm);
-          final double commonDenom = 0.5/a;
-          final double m1 = (-b + sqrtResult) * commonDenom;
-          assert Math.abs(a * m1 * m1 + b * m1 + c) < MINIMUM_RESOLUTION;
-          final double m2 = (-b - sqrtResult) * commonDenom;
-          assert Math.abs(a * m2 * m2 + b * m2 + c) < MINIMUM_RESOLUTION;
-          final double l1 = r * m1 + q;
-          final double l2 = r * m2 + q;
-          // x = ((1 - l*A) * ab^2 ) / (2 * m)
-          // y = (-l*B * ab^2) / ( 2 * m)
-          // z = (-l*C * c^2)/ (2 * m)
-          final double denom1 = 0.5 / m1;
-          final double denom2 = 0.5 / m2;
-          final GeoPoint thePoint1 = new GeoPoint((1.0-l1*A) * abSquared * denom1, -l1*B * abSquared * denom1, -l1*C * cSquared * denom1);
-          final GeoPoint thePoint2 = new GeoPoint((1.0-l2*A) * abSquared * denom2, -l2*B * abSquared * denom2, -l2*C * cSquared * denom2);
-          //Math is not quite accurate enough for this
-          //assert planetModel.pointOnSurface(thePoint1): "Point1: "+thePoint1+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
-          //  (thePoint1.x*thePoint1.x*planetModel.inverseAb*planetModel.inverseAb + thePoint1.y*thePoint1.y*planetModel.inverseAb*planetModel.inverseAb + thePoint1.z*thePoint1.z*planetModel.inverseC*planetModel.inverseC);
-          //assert planetModel.pointOnSurface(thePoint2): "Point1: "+thePoint2+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
-          //  (thePoint2.x*thePoint2.x*planetModel.inverseAb*planetModel.inverseAb + thePoint2.y*thePoint2.y*planetModel.inverseAb*planetModel.inverseAb + thePoint2.z*thePoint2.z*planetModel.inverseC*planetModel.inverseC);
-          //assert evaluateIsZero(thePoint1): "Evaluation of point1: "+evaluate(thePoint1);
-          //assert evaluateIsZero(thePoint2): "Evaluation of point2: "+evaluate(thePoint2);
-          addPoint(boundsInfo, bounds, thePoint1);
-          addPoint(boundsInfo, bounds, thePoint2);
-        } else {
-          // No solutions
-        }
-      } else if (Math.abs(b) > MINIMUM_RESOLUTION_SQUARED) {
-        //System.err.println("Not x quadratic");
-        // a = 0, so m = - c / b
-        final double m = -c / b;
-        final double l = r * m + q;
-        // x = ((1 - l*A) * ab^2 ) / (2 * m)
-        // y = (-l*B * ab^2) / ( 2 * m)
-        // z = (-l*C * c^2)/ (2 * m)
-        final double denom0 = 0.5 / m;
-        final GeoPoint thePoint = new GeoPoint((1.0-l*A) * abSquared * denom0, -l*B * abSquared * denom0, -l*C * cSquared * denom0);
-        //Math is not quite accurate enough for this
-        //assert planetModel.pointOnSurface(thePoint): "Point: "+thePoint+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
-        //  (thePoint.x*thePoint.x*planetModel.inverseAb*planetModel.inverseAb + thePoint.y*thePoint.y*planetModel.inverseAb*planetModel.inverseAb + thePoint.z*thePoint.z*planetModel.inverseC*planetModel.inverseC);
-        //assert evaluateIsZero(thePoint): "Evaluation of point: "+evaluate(thePoint);
-        addPoint(boundsInfo, bounds, thePoint);
-      } else {
-        // Something went very wrong; a = b = 0
-      }
-    }
-    
-    // Do Y
-    if (!boundsInfo.isSmallestMinY(planetModel) || !boundsInfo.isLargestMaxY(planetModel)) {
-      // For min/max x, we need to use lagrange multipliers.
-      //
-      // For this, we need grad(F(x,y,z)) = (dF/dx, dF/dy, dF/dz).
-      //
-      // Minimize and maximize f(x,y,z) = y, with respect to g(x,y,z) = Ax + By + Cz - D and h(x,y,z) = x^2/ab^2 + y^2/ab^2 + z^2/c^2 - 1
-      //
-      // grad(f(x,y,z)) = (0,1,0)
-      // grad(g(x,y,z)) = (A,B,C)
-      // grad(h(x,y,z)) = (2x/ab^2,2y/ab^2,2z/c^2)
-      //
-      // Equations we need to simultaneously solve:
-      // 
-      // grad(f(x,y,z)) = l * grad(g(x,y,z)) + m * grad(h(x,y,z))
-      // g(x,y,z) = 0
-      // h(x,y,z) = 0
-      // 
-      // Equations:
-      // 0 = l*A + m*2x/ab^2
-      // 1 = l*B + m*2y/ab^2
-      // 0 = l*C + m*2z/c^2
-      // Ax + By + Cz + D = 0
-      // x^2/ab^2 + y^2/ab^2 + z^2/c^2 - 1 = 0
-      // 
-      // Solve for x,y,z in terms of (l, m):
-      // 
-      // x = (-l*A * ab^2 ) / (2 * m)
-      // y = ((1 - l*B) * ab^2) / ( 2 * m)
-      // z = (-l*C * c^2)/ (2 * m)
-      // 
-      // Two equations, two unknowns:
-      // 
-      // A * ((-l*A * ab^2 ) / (2 * m)) + B * (((1 - l*B) * ab^2) / ( 2 * m)) + C * ((-l*C * c^2)/ (2 * m)) + D = 0
-      // 
-      // and
-      // 
-      // ((-l*A * ab^2 ) / (2 * m))^2/ab^2 + (((1 - l*B) * ab^2) / ( 2 * m))^2/ab^2 + ((-l*C * c^2)/ (2 * m))^2/c^2 - 1 = 0
-      // 
-      // Simple: solve for l and m, then find y from it.
-      // 
-      // (a) Use first equation to find l in terms of m.
-      // 
-      // A * ((-l*A * ab^2 ) / (2 * m)) + B * (((1 - l*B) * ab^2) / ( 2 * m)) + C * ((-l*C * c^2)/ (2 * m)) + D = 0
-      // A * (-l*A * ab^2 ) + B * ((1-l*B) * ab^2) + C * (-l*C * c^2) + D * 2 * m = 0
-      // -A^2*l*ab^2 + B*ab^2 - l*B^2*ab^2 - C^2*l*c^2 + D*2*m = 0
-      // - l *(A^2* ab^2 + B^2 * ab^2 + C^2 * c^2) + (B * ab^2 + D * 2 * m) = 0
-      // l = (B * ab^2 + D * 2 * m) / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
-      // l = B * ab^2 / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2) + m * 2 * D / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
-      // 
-      // For convenience:
-      // 
-      // k = 1.0 / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
-      // 
-      // Then:
-      // 
-      // l = B * ab^2 * k + m * 2 * D * k
-      // l = k * (B*ab^2 + m*2*D)
-      //
-      // For further convenience:
-      //
-      // q = B*ab^2*k
-      // r = 2*D*k
-      //
-      // l = (r*m + q)
-      // l^2 = (r^2 * m^2 + 2*r*m*q + q^2)
-      // 
-      // (b) Simplify the second equation before substitution
-      // 
-      // ((-l*A * ab^2 ) / (2 * m))^2/ab^2 + (((1 - l*B) * ab^2) / ( 2 * m))^2/ab^2 + ((-l*C * c^2)/ (2 * m))^2/c^2 - 1 = 0
-      // (-l*A * ab^2 )^2/ab^2 + ((1 - l*B) * ab^2)^2/ab^2 + (-l*C * c^2)^2/c^2 = 4 * m^2
-      // (-l*A)^2 * ab^2 + (1 - l*B)^2 * ab^2 + (-l*C)^2 * c^2 = 4 * m^2
-      // l^2*A^2 * ab^2 + (1 - 2*l*B + l^2*B^2) * ab^2 + l^2*C^2 * c^2 = 4 * m^2
-      // A^2*ab^2*l^2 + ab^2 - 2*B*ab^2*l + B^2*ab^2*l^2 + C^2*c^2*l^2 - 4*m^2 = 0
-      // 
-      // (c) Substitute for l, l^2
-      //
-      // A^2*ab^2*(r^2 * m^2 + 2*r*m*q + q^2) + ab^2 - 2*B*ab^2*(r*m + q) + B^2*ab^2*(r^2 * m^2 + 2*r*m*q + q^2) + C^2*c^2*(r^2 * m^2 + 2*r*m*q + q^2) - 4*m^2 = 0
-      // A^2*ab^2*r^2*m^2 + 2*A^2*ab^2*r*q*m + A^2*ab^2*q^2 + ab^2 - 2*B*ab^2*r*m - 2*B*ab^2*q + B^2*ab^2*r^2*m^2 +
-      //    2*B^2*ab^2*r*q*m + B^2*ab^2*q^2 + C^2*c^2*r^2*m^2 + 2*C^2*c^2*r*q*m + C^2*c^2*q^2 - 4*m^2 = 0
-      //
-      // (d) Group
-      //
-      // m^2 * [A^2*ab^2*r^2 + B^2*ab^2*r^2 + C^2*c^2*r^2 - 4] +
-      // m * [2*A^2*ab^2*r*q - 2*B*ab^2*r + 2*B^2*ab^2*r*q + 2*C^2*c^2*r*q] +
-      // [A^2*ab^2*q^2 + ab^2 - 2*B*ab^2*q + B^2*ab^2*q^2 + C^2*c^2*q^2]  =  0
-
-      //System.err.println("    computing Y bound");
-      
-      // Useful subexpressions for this bound
-      final double q = B*abSquared*k;
-      final double qSquared = q * q;
-
-      // Quadratic equation
-      final double a = ASquared*abSquared*rSquared + BSquared*abSquared*rSquared + CSquared*cSquared*rSquared - 4.0;
-      final double b = 2.0*ASquared*abSquared*r*q - 2.0*B*abSquared*r + 2.0*BSquared*abSquared*r*q + 2.0*CSquared*cSquared*r*q;
-      final double c = ASquared*abSquared*qSquared + abSquared - 2.0*B*abSquared*q + BSquared*abSquared*qSquared + CSquared*cSquared*qSquared;
-
-      if (Math.abs(a) >= MINIMUM_RESOLUTION_SQUARED) {
-        final double sqrtTerm = b*b - 4.0*a*c;
-        if (Math.abs(sqrtTerm) < MINIMUM_RESOLUTION_SQUARED) {
-          // One solution
-          final double m = -b / (2.0 * a);
-          final double l = r * m + q;
-          // x = (-l*A * ab^2 ) / (2 * m)
-          // y = ((1.0-l*B) * ab^2) / ( 2 * m)
-          // z = (-l*C * c^2)/ (2 * m)
-          final double denom0 = 0.5 / m;
-          final GeoPoint thePoint = new GeoPoint(-l*A * abSquared * denom0, (1.0-l*B) * abSquared * denom0, -l*C * cSquared * denom0);
-          //Math is not quite accurate enough for this
-          //assert planetModel.pointOnSurface(thePoint): "Point: "+thePoint+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
-          //  (thePoint1.x*thePoint.x*planetModel.inverseAb*planetModel.inverseAb + thePoint.y*thePoint.y*planetModel.inverseAb*planetModel.inverseAb + thePoint.z*thePoint.z*planetModel.inverseC*planetModel.inverseC);
-          //assert evaluateIsZero(thePoint): "Evaluation of point: "+evaluate(thePoint);
-          addPoint(boundsInfo, bounds, thePoint);
-        } else if (sqrtTerm > 0.0) {
-          // Two solutions
-          final double sqrtResult = Math.sqrt(sqrtTerm);
-          final double commonDenom = 0.5/a;
-          final double m1 = (-b + sqrtResult) * commonDenom;
-          assert Math.abs(a * m1 * m1 + b * m1 + c) < MINIMUM_RESOLUTION;
-          final double m2 = (-b - sqrtResult) * commonDenom;
-          assert Math.abs(a * m2 * m2 + b * m2 + c) < MINIMUM_RESOLUTION;
-          final double l1 = r * m1 + q;
-          final double l2 = r * m2 + q;
-          // x = (-l*A * ab^2 ) / (2 * m)
-          // y = ((1.0-l*B) * ab^2) / ( 2 * m)
-          // z = (-l*C * c^2)/ (2 * m)
-          final double denom1 = 0.5 / m1;
-          final double denom2 = 0.5 / m2;
-          final GeoPoint thePoint1 = new GeoPoint(-l1*A * abSquared * denom1, (1.0-l1*B) * abSquared * denom1, -l1*C * cSquared * denom1);
-          final GeoPoint thePoint2 = new GeoPoint(-l2*A * abSquared * denom2, (1.0-l2*B) * abSquared * denom2, -l2*C * cSquared * denom2);
-          //Math is not quite accurate enough for this
-          //assert planetModel.pointOnSurface(thePoint1): "Point1: "+thePoint1+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
-          //  (thePoint1.x*thePoint1.x*planetModel.inverseAb*planetModel.inverseAb + thePoint1.y*thePoint1.y*planetModel.inverseAb*planetModel.inverseAb + thePoint1.z*thePoint1.z*planetModel.inverseC*planetModel.inverseC);
-          //assert planetModel.pointOnSurface(thePoint2): "Point2: "+thePoint2+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
-          //  (thePoint2.x*thePoint2.x*planetModel.inverseAb*planetModel.inverseAb + thePoint2.y*thePoint2.y*planetModel.inverseAb*planetModel.inverseAb + thePoint2.z*thePoint2.z*planetModel.inverseC*planetModel.inverseC);
-          //assert evaluateIsZero(thePoint1): "Evaluation of point1: "+evaluate(thePoint1);
-          //assert evaluateIsZero(thePoint2): "Evaluation of point2: "+evaluate(thePoint2);
-          addPoint(boundsInfo, bounds, thePoint1);
-          addPoint(boundsInfo, bounds, thePoint2);
-        } else {
-          // No solutions
-        }
-      } else if (Math.abs(b) > MINIMUM_RESOLUTION_SQUARED) {
-        // a = 0, so m = - c / b
-        final double m = -c / b;
-        final double l = r * m + q;
-        // x = ( -l*A * ab^2 ) / (2 * m)
-        // y = ((1-l*B) * ab^2) / ( 2 * m)
-        // z = (-l*C * c^2)/ (2 * m)
-        final double denom0 = 0.5 / m;
-        final GeoPoint thePoint = new GeoPoint(-l*A * abSquared * denom0, (1.0-l*B) * abSquared * denom0, -l*C * cSquared * denom0);
-        //Math is not quite accurate enough for this
-        //assert planetModel.pointOnSurface(thePoint): "Point: "+thePoint+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
-        //  (thePoint.x*thePoint.x*planetModel.inverseAb*planetModel.inverseAb + thePoint.y*thePoint.y*planetModel.inverseAb*planetModel.inverseAb + thePoint.z*thePoint.z*planetModel.inverseC*planetModel.inverseC);
-        //assert evaluateIsZero(thePoint): "Evaluation of point: "+evaluate(thePoint);
-        addPoint(boundsInfo, bounds, thePoint);
-      } else {
-        // Something went very wrong; a = b = 0
-      }
-    }
-  }
-  
-  /**
-   * Accumulate bounds information for this plane, intersected with the unit sphere.
-   * Updates both latitude and longitude information, using max/min points found
-   * within the specified bounds.
-   *
-   * @param planetModel is the planet model to use in determining bounds.
-   * @param boundsInfo is the lat/lon info to update with additional bounding information.
-   * @param bounds     are the surfaces delineating what's inside the shape.
-   */
-  public void recordBounds(final PlanetModel planetModel, final LatLonBounds boundsInfo, final Membership... bounds) {
-    // For clarity, load local variables with good names
-    final double A = this.x;
-    final double B = this.y;
-    final double C = this.z;
-
-    // Now compute latitude min/max points
-    if (!boundsInfo.checkNoTopLatitudeBound() || !boundsInfo.checkNoBottomLatitudeBound()) {
-      //System.err.println("Looking at latitude for plane "+this);
-      // With ellipsoids, we really have only one viable way to do this computation.
-      // Specifically, we compute an appropriate vertical plane, based on the current plane's x-y orientation, and
-      // then intersect it with this one and with the ellipsoid.  This gives us zero, one, or two points to use
-      // as bounds.
-      // There is one special case: horizontal circles.  These require TWO vertical planes: one for the x, and one for
-      // the y, and we use all four resulting points in the bounds computation.
-      if ((Math.abs(A) >= MINIMUM_RESOLUTION || Math.abs(B) >= MINIMUM_RESOLUTION)) {
-        // NOT a horizontal circle!
-        //System.err.println(" Not a horizontal circle");
-        final Plane verticalPlane = constructNormalizedZPlane(A,B);
-        final GeoPoint[] points = findIntersections(planetModel, verticalPlane, bounds, NO_BOUNDS);
-        for (final GeoPoint point : points) {
-          addPoint(boundsInfo, bounds, point);
-        }
-      } else {
-        // Horizontal circle.  Since a==b, any vertical plane suffices.
-        final GeoPoint[] points = findIntersections(planetModel, normalXPlane, NO_BOUNDS, NO_BOUNDS);
-        boundsInfo.addZValue(points[0]);
-      }
-      //System.err.println("Done latitude bounds");
-    }
-
-    // First, figure out our longitude bounds, unless we no longer need to consider that
-    if (!boundsInfo.checkNoLongitudeBound()) {
-      //System.err.println("Computing longitude bounds for "+this);
-      //System.out.println("A = "+A+" B = "+B+" C = "+C+" D = "+D);
-      // Compute longitude bounds
-
-      double a;
-      double b;
-      double c;
-
-      if (Math.abs(C) < MINIMUM_RESOLUTION) {
-        // Degenerate; the equation describes a line
-        //System.out.println("It's a zero-width ellipse");
-        // Ax + By + D = 0
-        if (Math.abs(D) >= MINIMUM_RESOLUTION) {
-          if (Math.abs(A) > Math.abs(B)) {
-            // Use equation suitable for A != 0
-            // We need to find the endpoints of the zero-width ellipse.
-            // Geometrically, we have a line segment in x-y space.  We need to locate the endpoints
-            // of that line.  But luckily, we know some things: specifically, since it is a
-            // degenerate situation in projection, the C value had to have been 0.  That
-            // means that our line's endpoints will coincide with the projected ellipse.  All we
-            // need to do then is to find the intersection of the projected ellipse and the line
-            // equation:
-            //
-            // A x + B y + D = 0
-            //
-            // Since A != 0:
-            // x = (-By - D)/A
-            //
-            // The projected ellipse:
-            // x^2/a^2 + y^2/b^2 - 1 = 0
-            // Substitute:
-            // [(-By-D)/A]^2/a^2 + y^2/b^2 -1 = 0
-            // Multiply through by A^2:
-            // [-By - D]^2/a^2 + A^2*y^2/b^2 - A^2 = 0
-            // Multiply out:
-            // B^2*y^2/a^2 + 2BDy/a^2 + D^2/a^2 + A^2*y^2/b^2 - A^2 = 0
-            // Group:
-            // y^2 * [B^2/a^2 + A^2/b^2] + y [2BD/a^2] + [D^2/a^2-A^2] = 0
-
-            a = B * B * planetModel.inverseAbSquared + A * A * planetModel.inverseAbSquared;
-            b = 2.0 * B * D * planetModel.inverseAbSquared;
-            c = D * D * planetModel.inverseAbSquared - A * A;
-
-            double sqrtClause = b * b - 4.0 * a * c;
-
-            if (Math.abs(sqrtClause) < MINIMUM_RESOLUTION_SQUARED) {
-              double y0 = -b / (2.0 * a);
-              double x0 = (-D - B * y0) / A;
-              double z0 = 0.0;
-              addPoint(boundsInfo, bounds, new GeoPoint(x0, y0, z0));
-            } else if (sqrtClause > 0.0) {
-              double sqrtResult = Math.sqrt(sqrtClause);
-              double denom = 1.0 / (2.0 * a);
-              double Hdenom = 1.0 / A;
-
-              double y0a = (-b + sqrtResult) * denom;
-              double y0b = (-b - sqrtResult) * denom;
-
-              double x0a = (-D - B * y0a) * Hdenom;
-              double x0b = (-D - B * y0b) * Hdenom;
-
-              double z0a = 0.0;
-              double z0b = 0.0;
-
-              addPoint(boundsInfo, bounds, new GeoPoint(x0a, y0a, z0a));
-              addPoint(boundsInfo, bounds, new GeoPoint(x0b, y0b, z0b));
-            }
-
-          } else {
-            // Use equation suitable for B != 0
-            // Since I != 0, we rewrite:
-            // y = (-Ax - D)/B
-            a = B * B * planetModel.inverseAbSquared + A * A * planetModel.inverseAbSquared;
-            b = 2.0 * A * D * planetModel.inverseAbSquared;
-            c = D * D * planetModel.inverseAbSquared - B * B;
-
-            double sqrtClause = b * b - 4.0 * a * c;
-
-            if (Math.abs(sqrtClause) < MINIMUM_RESOLUTION_SQUARED) {
-              double x0 = -b / (2.0 * a);
-              double y0 = (-D - A * x0) / B;
-              double z0 = 0.0;
-              addPoint(boundsInfo, bounds, new GeoPoint(x0, y0, z0));
-            } else if (sqrtClause > 0.0) {
-              double sqrtResult = Math.sqrt(sqrtClause);
-              double denom = 1.0 / (2.0 * a);
-              double Idenom = 1.0 / B;
-
-              double x0a = (-b + sqrtResult) * denom;
-              double x0b = (-b - sqrtResult) * denom;
-              double y0a = (-D - A * x0a) * Idenom;
-              double y0b = (-D - A * x0b) * Idenom;
-              double z0a = 0.0;
-              double z0b = 0.0;
-
-              addPoint(boundsInfo, bounds, new GeoPoint(x0a, y0a, z0a));
-              addPoint(boundsInfo, bounds, new GeoPoint(x0b, y0b, z0b));
-            }
-          }
-        }
-
-      } else {
-        //System.err.println("General longitude bounds...");
-
-        // NOTE WELL: The x,y,z values generated here are NOT on the unit sphere.
-        // They are for lat/lon calculation purposes only.  x-y is meant to be used for longitude determination,
-        // and z for latitude, and that's all the values are good for.
-
-        // (1) Intersect the plane and the ellipsoid, and project the results into the x-y plane:
-        // From plane:
-        // z = (-Ax - By - D) / C
-        // From ellipsoid:
-        // x^2/a^2 + y^2/b^2 + [(-Ax - By - D) / C]^2/c^2 = 1
-        // Simplify/expand:
-        // C^2*x^2/a^2 + C^2*y^2/b^2 + (-Ax - By - D)^2/c^2 = C^2
-        //
-        // x^2 * C^2/a^2 + y^2 * C^2/b^2 + x^2 * A^2/c^2 + ABxy/c^2 + ADx/c^2 + ABxy/c^2 + y^2 * B^2/c^2 + BDy/c^2 + ADx/c^2 + BDy/c^2 + D^2/c^2 = C^2
-        // Group:
-        // [A^2/c^2 + C^2/a^2] x^2 + [B^2/c^2 + C^2/b^2] y^2 + [2AB/c^2]xy + [2AD/c^2]x + [2BD/c^2]y + [D^2/c^2-C^2] = 0
-        // For convenience, introduce post-projection coefficient variables to make life easier.
-        // E x^2 + F y^2 + G xy + H x + I y + J = 0
-        double E = A * A * planetModel.inverseCSquared + C * C * planetModel.inverseAbSquared;
-        double F = B * B * planetModel.inverseCSquared + C * C * planetModel.inverseAbSquared;
-        double G = 2.0 * A * B * planetModel.inverseCSquared;
-        double H = 2.0 * A * D * planetModel.inverseCSquared;
-        double I = 2.0 * B * D * planetModel.inverseCSquared;
-        double J = D * D * planetModel.inverseCSquared - C * C;
-
-        //System.err.println("E = " + E + " F = " + F + " G = " + G + " H = "+ H + " I = " + I + " J = " + J);
-
-        // Check if the origin is within, by substituting x = 0, y = 0 and seeing if less than zero
-        if (Math.abs(J) >= MINIMUM_RESOLUTION && J > 0.0) {
-          // The derivative of the curve above is:
-          // 2Exdx + 2Fydy + G(xdy+ydx) + Hdx + Idy = 0
-          // (2Ex + Gy + H)dx + (2Fy + Gx + I)dy = 0
-          // dy/dx = - (2Ex + Gy + H) / (2Fy + Gx + I)
-          //
-          // The equation of a line going through the origin with the slope dy/dx is:
-          // y = dy/dx x
-          // y = - (2Ex + Gy + H) / (2Fy + Gx + I)  x
-          // Rearrange:
-          // (2Fy + Gx + I) y + (2Ex + Gy + H) x = 0
-          // 2Fy^2 + Gxy + Iy + 2Ex^2 + Gxy + Hx = 0
-          // 2Ex^2 + 2Fy^2 + 2Gxy + Hx + Iy = 0
-          //
-          // Multiply the original equation by 2:
-          // 2E x^2 + 2F y^2 + 2G xy + 2H x + 2I y + 2J = 0
-          // Subtract one from the other, to remove the high-order terms:
-          // Hx + Iy + 2J = 0
-          // Now, we can substitute either x = or y = into the derivative equation, or into the original equation.
-          // But we will need to base this on which coefficient is non-zero
-
-          if (Math.abs(H) > Math.abs(I)) {
-            //System.err.println(" Using the y quadratic");
-            // x = (-2J - Iy)/H
-
-            // Plug into the original equation:
-            // E [(-2J - Iy)/H]^2 + F y^2 + G [(-2J - Iy)/H]y + H [(-2J - Iy)/H] + I y + J = 0
-            // E [(-2J - Iy)/H]^2 + F y^2 + G [(-2J - Iy)/H]y - J = 0
-            // Same equation as derivative equation, except for a factor of 2!  So it doesn't matter which we pick.
-
-            // Plug into derivative equation:
-            // 2E[(-2J - Iy)/H]^2 + 2Fy^2 + 2G[(-2J - Iy)/H]y + H[(-2J - Iy)/H] + Iy = 0
-            // 2E[(-2J - Iy)/H]^2 + 2Fy^2 + 2G[(-2J - Iy)/H]y - 2J = 0
-            // E[(-2J - Iy)/H]^2 + Fy^2 + G[(-2J - Iy)/H]y - J = 0
-
-            // Multiply by H^2 to make manipulation easier
-            // E[(-2J - Iy)]^2 + F*H^2*y^2 + GH[(-2J - Iy)]y - J*H^2 = 0
-            // Do the square
-            // E[4J^2 + 4IJy + I^2*y^2] + F*H^2*y^2 + GH(-2Jy - I*y^2) - J*H^2 = 0
-
-            // Multiply it out
-            // 4E*J^2 + 4EIJy + E*I^2*y^2 + H^2*Fy^2 - 2GHJy - GH*I*y^2 - J*H^2 = 0
-            // Group:
-            // y^2 [E*I^2 - GH*I + F*H^2] + y [4EIJ - 2GHJ] + [4E*J^2 - J*H^2] = 0
-
-            a = E * I * I - G * H * I + F * H * H;
-            b = 4.0 * E * I * J - 2.0 * G * H * J;
-            c = 4.0 * E * J * J - J * H * H;
-
-            //System.out.println("a="+a+" b="+b+" c="+c);
-            double sqrtClause = b * b - 4.0 * a * c;
-            //System.out.println("sqrtClause="+sqrtClause);
-
-            if (Math.abs(sqrtClause) < MINIMUM_RESOLUTION_CUBED) {
-              //System.err.println(" One solution");
-              double y0 = -b / (2.0 * a);
-              double x0 = (-2.0 * J - I * y0) / H;
-              double z0 = (-A * x0 - B * y0 - D) / C;
-
-              addPoint(boundsInfo, bounds, new GeoPoint(x0, y0, z0));
-            } else if (sqrtClause > 0.0) {
-              //System.err.println(" Two solutions");
-              double sqrtResult = Math.sqrt(sqrtClause);
-              double denom = 1.0 / (2.0 * a);
-              double Hdenom = 1.0 / H;
-              double Cdenom = 1.0 / C;
-
-              double y0a = (-b + sqrtResult) * denom;
-              double y0b = (-b - sqrtResult) * denom;
-              double x0a = (-2.0 * J - I * y0a) * Hdenom;
-              double x0b = (-2.0 * J - I * y0b) * Hdenom;
-              double z0a = (-A * x0a - B * y0a - D) * Cdenom;
-              double z0b = (-A * x0b - B * y0b - D) * Cdenom;
-
-              addPoint(boundsInfo, bounds, new GeoPoint(x0a, y0a, z0a));
-              addPoint(boundsInfo, bounds, new GeoPoint(x0b, y0b, z0b));
-            }
-
-          } else {
-            //System.err.println(" Using the x quadratic");
-            // y = (-2J - Hx)/I
-
-            // Plug into the original equation:
-            // E x^2 + F [(-2J - Hx)/I]^2 + G x[(-2J - Hx)/I] - J = 0
-
-            // Multiply by I^2 to make manipulation easier
-            // E * I^2 * x^2 + F [(-2J - Hx)]^2 + GIx[(-2J - Hx)] - J * I^2 = 0
-            // Do the square
-            // E * I^2 * x^2 + F [ 4J^2 + 4JHx + H^2*x^2] + GI[(-2Jx - H*x^2)] - J * I^2 = 0
-
-            // Multiply it out
-            // E * I^2 * x^2 + 4FJ^2 + 4FJHx + F*H^2*x^2 - 2GIJx - HGI*x^2 - J * I^2 = 0
-            // Group:
-            // x^2 [E*I^2 - GHI + F*H^2] + x [4FJH - 2GIJ] + [4FJ^2 - J*I^2] = 0
-
-            // E x^2 + F y^2 + G xy + H x + I y + J = 0
-
-            a = E * I * I - G * H * I + F * H * H;
-            b = 4.0 * F * H * J - 2.0 * G * I * J;
-            c = 4.0 * F * J * J - J * I * I;
-
-            //System.out.println("a="+a+" b="+b+" c="+c);
-            double sqrtClause = b * b - 4.0 * a * c;
-            //System.out.println("sqrtClause="+sqrtClause);
-            if (Math.abs(sqrtClause) < MINIMUM_RESOLUTION_CUBED) {
-              //System.err.println(" One solution; sqrt clause was "+sqrtClause);
-              double x0 = -b / (2.0 * a);
-              double y0 = (-2.0 * J - H * x0) / I;
-              double z0 = (-A * x0 - B * y0 - D) / C;
-              // Verify that x&y fulfill the equation
-              // 2Ex^2 + 2Fy^2 + 2Gxy + Hx + Iy = 0
-              addPoint(boundsInfo, bounds, new GeoPoint(x0, y0, z0));
-            } else if (sqrtClause > 0.0) {
-              //System.err.println(" Two solutions");
-              double sqrtResult = Math.sqrt(sqrtClause);
-              double denom = 1.0 / (2.0 * a);
-              double Idenom = 1.0 / I;
-              double Cdenom = 1.0 / C;
-
-              double x0a = (-b + sqrtResult) * denom;
-              double x0b = (-b - sqrtResult) * denom;
-              double y0a = (-2.0 * J - H * x0a) * Idenom;
-              double y0b = (-2.0 * J - H * x0b) * Idenom;
-              double z0a = (-A * x0a - B * y0a - D) * Cdenom;
-              double z0b = (-A * x0b - B * y0b - D) * Cdenom;
-
-              addPoint(boundsInfo, bounds, new GeoPoint(x0a, y0a, z0a));
-              addPoint(boundsInfo, bounds, new GeoPoint(x0b, y0b, z0b));
-            }
-          }
-        }
-      }
-    }
-
-  }
-
-  /** Add a point to boundsInfo if within a specifically bounded area.
-   * @param boundsInfo is the object to be modified.
-   * @param bounds is the area that the point must be within.
-   * @param point is the point.
-   */
-  protected static void addPoint(final Bounds boundsInfo, final Membership[] bounds, final GeoPoint point) {
-    // Make sure the discovered point is within the bounds
-    for (Membership bound : bounds) {
-      if (!bound.isWithin(point))
-        return;
-    }
-    // Add the point
-    boundsInfo.addPoint(point);
-  }
-
-  /** Add a point to boundsInfo if within a specifically bounded area.
-   * @param boundsInfo is the object to be modified.
-   * @param bounds is the area that the point must be within.
-   * @param x is the x value.
-   * @param y is the y value.
-   * @param z is the z value.
-   */
-  /*
-  protected static void addPoint(final Bounds boundsInfo, final Membership[] bounds, final double x, final double y, final double z) {
-    //System.err.println(" Want to add point x="+x+" y="+y+" z="+z);
-    // Make sure the discovered point is within the bounds
-    for (Membership bound : bounds) {
-      if (!bound.isWithin(x, y, z))
-        return;
-    }
-    // Add the point
-    //System.err.println("  point added");
-    //System.out.println("Adding point x="+x+" y="+y+" z="+z);
-    boundsInfo.addPoint(x, y, z);
-  }
-  */
-
-  /**
-   * Determine whether the plane intersects another plane within the
-   * bounds provided.
-   *
-   * @param planetModel is the planet model to use in determining intersection.
-   * @param q                 is the other plane.
-   * @param notablePoints     are points to look at to disambiguate cases when the two planes are identical.
-   * @param moreNotablePoints are additional points to look at to disambiguate cases when the two planes are identical.
-   * @param bounds            is one part of the bounds.
-   * @param moreBounds        are more bounds.
-   * @return true if there's an intersection.
-   */
-  public boolean intersects(final PlanetModel planetModel, final Plane q, final GeoPoint[] notablePoints, final GeoPoint[] moreNotablePoints, final Membership[] bounds, final Membership... moreBounds) {
-    //System.err.println("Does plane "+this+" intersect with plane "+q);
-    // If the two planes are identical, then the math will find no points of intersection.
-    // So a special case of this is to check for plane equality.  But that is not enough, because
-    // what we really need at that point is to determine whether overlap occurs between the two parts of the intersection
-    // of plane and circle.  That is, are there *any* points on the plane that are within the bounds described?
-    if (isNumericallyIdentical(q)) {
-      //System.err.println(" Identical plane");
-      // The only way to efficiently figure this out will be to have a list of trial points available to evaluate.
-      // We look for any point that fulfills all the bounds.
-      for (GeoPoint p : notablePoints) {
-        if (meetsAllBounds(p, bounds, moreBounds)) {
-          //System.err.println("  found a notable point in bounds, so intersects");
-          return true;
-        }
-      }
-      for (GeoPoint p : moreNotablePoints) {
-        if (meetsAllBounds(p, bounds, moreBounds)) {
-          //System.err.println("  found a notable point in bounds, so intersects");
-          return true;
-        }
-      }
-      //System.err.println("  no notable points inside found; no intersection");
-      return false;
-    }
-    return findIntersections(planetModel, q, bounds, moreBounds).length > 0;
-  }
-
-  /**
-   * Returns true if this plane and the other plane are identical within the margin of error.
-   * @param p is the plane to compare against.
-   * @return true if the planes are numerically identical.
-   */
-  protected boolean isNumericallyIdentical(final Plane p) {
-    // We can get the correlation by just doing a parallel plane check.  If that passes, then compute a point on the plane
-    // (using D) and see if it also on the other plane.
-    if (Math.abs(this.y * p.z - this.z * p.y) >= MINIMUM_RESOLUTION)
-      return false;
-    if (Math.abs(this.z * p.x - this.x * p.z) >= MINIMUM_RESOLUTION)
-      return false;
-    if (Math.abs(this.x * p.y - this.y * p.x) >= MINIMUM_RESOLUTION)
-      return false;
-
-    // Now, see whether the parallel planes are in fact on top of one another.
-    // The math:
-    // We need a single point that fulfills:
-    // Ax + By + Cz + D = 0
-    // Pick:
-    // x0 = -(A * D) / (A^2 + B^2 + C^2)
-    // y0 = -(B * D) / (A^2 + B^2 + C^2)
-    // z0 = -(C * D) / (A^2 + B^2 + C^2)
-    // Check:
-    // A (x0) + B (y0) + C (z0) + D =? 0
-    // A (-(A * D) / (A^2 + B^2 + C^2)) + B (-(B * D) / (A^2 + B^2 + C^2)) + C (-(C * D) / (A^2 + B^2 + C^2)) + D ?= 0
-    // -D [ A^2 / (A^2 + B^2 + C^2) + B^2 / (A^2 + B^2 + C^2) + C^2 / (A^2 + B^2 + C^2)] + D ?= 0
-    // Yes.
-    final double denom = 1.0 / (p.x * p.x + p.y * p.y + p.z * p.z);
-    return evaluateIsZero(-p.x * p.D * denom, -p.y * p.D * denom, -p.z * p.D * denom);
-  }
-
-  /**
-   * Check if a vector meets the provided bounds.
-   * @param p is the vector.
-   * @param bounds are the bounds.
-   * @return true if the vector describes a point within the bounds.
-   */
-  protected static boolean meetsAllBounds(final Vector p, final Membership[] bounds) {
-    return meetsAllBounds(p.x, p.y, p.z, bounds);
-  }
-
-  /**
-   * Check if a vector meets the provided bounds.
-   * @param x is the x value.
-   * @param y is the y value.
-   * @param z is the z value.
-   * @param bounds are the bounds.
-   * @return true if the vector describes a point within the bounds.
-   */
-  protected static boolean meetsAllBounds(final double x, final double y, final double z, final Membership[] bounds) {
-    for (final Membership bound : bounds) {
-      if (!bound.isWithin(x,y,z))
-        return false;
-    }
-    return true;
-  }
-
-  /**
-   * Check if a vector meets the provided bounds.
-   * @param p is the vector.
-   * @param bounds are the bounds.
-   * @param moreBounds are an additional set of bounds.
-   * @return true if the vector describes a point within the bounds.
-   */
-  protected static boolean meetsAllBounds(final Vector p, final Membership[] bounds, final Membership[] moreBounds) {
-    return meetsAllBounds(p.x, p.y, p.z, bounds, moreBounds);
-  }
-
-  /**
-   * Check if a vector meets the provided bounds.
-   * @param x is the x value.
-   * @param y is the y value.
-   * @param z is the z value.
-   * @param bounds are the bounds.
-   * @param moreBounds are an additional set of bounds.
-   * @return true if the vector describes a point within the bounds.
-   */
-  protected static boolean meetsAllBounds(final double x, final double y, final double z, final Membership[] bounds,
-                                          final Membership[] moreBounds) {
-    return meetsAllBounds(x,y,z, bounds) && meetsAllBounds(x,y,z, moreBounds);
-  }
-
-  /**
-   * Find a sample point on the intersection between two planes and the world.
-   * @param planetModel is the planet model.
-   * @param q is the second plane to consider.
-   * @return a sample point that is on the intersection between the two planes and the world.
-   */
-  public GeoPoint getSampleIntersectionPoint(final PlanetModel planetModel, final Plane q) {
-    final GeoPoint[] intersections = findIntersections(planetModel, q, NO_BOUNDS, NO_BOUNDS);
-    if (intersections.length == 0)
-      return null;
-    return intersections[0];
-  }
-
-  @Override
-  public String toString() {
-    return "[A=" + x + ", B=" + y + "; C=" + z + "; D=" + D + "]";
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!super.equals(o))
-      return false;
-    if (!(o instanceof Plane))
-      return false;
-    Plane other = (Plane) o;
-    return other.D == D;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    long temp;
-    temp = Double.doubleToLongBits(D);
-    result = 31 * result + (int) (temp ^ (temp >>> 32));
-    return result;
-  }
-}


[04/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 0093e26)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/SidedPlane.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/SidedPlane.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/SidedPlane.java
new file mode 100755
index 0000000..e080bc0
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/SidedPlane.java
@@ -0,0 +1,175 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Combination of a plane, and a sign value indicating what evaluation values are on the correct
+ * side of the plane.
+ *
+ * @lucene.experimental
+ */
+public class SidedPlane extends Plane implements Membership {
+  /** The sign value for evaluation of a point on the correct side of the plane */
+  public final double sigNum;
+
+  /**
+   * Construct a SidedPlane identical to an existing one, but reversed.
+   *
+   * @param sidedPlane is the existing plane.
+   */
+  public SidedPlane(SidedPlane sidedPlane) {
+    super(sidedPlane, sidedPlane.D);
+    this.sigNum = -sidedPlane.sigNum;
+  }
+
+  /**
+   * Construct a sided plane from a pair of vectors describing points, and including
+   * origin, plus a point p which describes the side.
+   *
+   * @param p point to evaluate
+   * @param A is the first in-plane point
+   * @param B is the second in-plane point
+   */
+  public SidedPlane(Vector p, Vector A, Vector B) {
+    super(A, B);
+    sigNum = Math.signum(evaluate(p));
+    if (sigNum == 0.0)
+      throw new IllegalArgumentException("Cannot determine sidedness because check point is on plane.");
+  }
+
+  /**
+   * Construct a sided plane from a point and a Z coordinate.
+   *
+   * @param p      point to evaluate.
+   * @param planetModel is the planet model.
+   * @param sinLat is the sin of the latitude of the plane.
+   */
+  public SidedPlane(Vector p, final PlanetModel planetModel, double sinLat) {
+    super(planetModel, sinLat);
+    sigNum = Math.signum(evaluate(p));
+    if (sigNum == 0.0)
+      throw new IllegalArgumentException("Cannot determine sidedness because check point is on plane.");
+  }
+
+  /**
+   * Construct a sided vertical plane from a point and specified x and y coordinates.
+   *
+   * @param p point to evaluate.
+   * @param x is the specified x.
+   * @param y is the specified y.
+   */
+  public SidedPlane(Vector p, double x, double y) {
+    super(x, y);
+    sigNum = Math.signum(evaluate(p));
+    if (sigNum == 0.0)
+      throw new IllegalArgumentException("Cannot determine sidedness because check point is on plane.");
+  }
+
+  /**
+   * Construct a sided plane with a normal vector and offset.
+   *
+   * @param p point to evaluate.
+   * @param v is the normal vector.
+   * @param D is the origin offset for the plan.
+   */
+  public SidedPlane(Vector p, Vector v, double D) {
+    super(v, D);
+    sigNum = Math.signum(evaluate(p));
+    if (sigNum == 0.0)
+      throw new IllegalArgumentException("Cannot determine sidedness because check point is on plane.");
+  }
+
+  /**
+   * Construct a sided plane with a normal vector and offset.
+   *
+   * @param pX X coord of point to evaluate.
+   * @param pY Y coord of point to evaluate.
+   * @param pZ Z coord of point to evaluate.
+   * @param v is the normal vector.
+   * @param D is the origin offset for the plan.
+   */
+  public SidedPlane(double pX, double pY, double pZ, Vector v, double D) {
+    super(v, D);
+    sigNum = Math.signum(evaluate(pX,pY,pZ));
+    if (sigNum == 0.0)
+      throw new IllegalArgumentException("Cannot determine sidedness because check point is on plane.");
+  }
+
+  /** Construct a sided plane from two points and a third normal vector.
+   */
+  public static SidedPlane constructNormalizedPerpendicularSidedPlane(final Vector insidePoint,
+    final Vector normalVector, final Vector point1, final Vector point2) {
+    final Vector pointsVector = new Vector(point1.x - point2.x, point1.y - point2.y, point1.z - point2.z);
+    final Vector newNormalVector = new Vector(normalVector, pointsVector);
+    try {
+      // To construct the plane, we now just need D, which is simply the negative of the evaluation of the circle normal vector at one of the points.
+      return new SidedPlane(insidePoint, newNormalVector, -newNormalVector.dotProduct(point1));
+    } catch (IllegalArgumentException e) {
+      return null;
+    }
+  }
+  
+  /** Construct a sided plane from three points.
+   */
+  public static SidedPlane constructNormalizedThreePointSidedPlane(final Vector insidePoint,
+    final Vector point1, final Vector point2, final Vector point3) {
+    try {
+      final Vector planeNormal = new Vector(
+        new Vector(point1.x - point2.x, point1.y - point2.y, point1.z - point2.z),
+        new Vector(point2.x - point3.x, point2.y - point3.y, point2.z - point3.z));
+      return new SidedPlane(insidePoint, planeNormal, -planeNormal.dotProduct(point2));
+    } catch (IllegalArgumentException e) {
+      return null;
+    }
+  }
+
+  @Override
+  public boolean isWithin(double x, double y, double z) {
+    double evalResult = evaluate(x, y, z);
+    if (Math.abs(evalResult) < MINIMUM_RESOLUTION)
+      return true;
+    double sigNum = Math.signum(evalResult);
+    return sigNum == this.sigNum;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (!(o instanceof SidedPlane)) return false;
+    if (!super.equals(o)) return false;
+
+    SidedPlane that = (SidedPlane) o;
+
+    return Double.compare(that.sigNum, sigNum) == 0;
+
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    long temp;
+    temp = Double.doubleToLongBits(sigNum);
+    result = 31 * result + (int) (temp ^ (temp >>> 32));
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "[A=" + x + ", B=" + y + ", C=" + z + ", D=" + D + ", side=" + sigNum + "]";
+  }
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/StandardXYZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/StandardXYZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/StandardXYZSolid.java
new file mode 100644
index 0000000..492f7b4
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/StandardXYZSolid.java
@@ -0,0 +1,417 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * 3D rectangle, bounded on six sides by X,Y,Z limits
+ *
+ * @lucene.internal
+ */
+public class StandardXYZSolid extends BaseXYZSolid {
+
+  /** Whole world? */
+  protected final boolean isWholeWorld;
+  /** Min-X plane */
+  protected final SidedPlane minXPlane;
+  /** Max-X plane */
+  protected final SidedPlane maxXPlane;
+  /** Min-Y plane */
+  protected final SidedPlane minYPlane;
+  /** Max-Y plane */
+  protected final SidedPlane maxYPlane;
+  /** Min-Z plane */
+  protected final SidedPlane minZPlane;
+  /** Max-Z plane */
+  protected final SidedPlane maxZPlane;
+  
+  /** These are the edge points of the shape, which are defined to be at least one point on
+   * each surface area boundary.  In the case of a solid, this includes points which represent
+   * the intersection of XYZ bounding planes and the planet, as well as points representing
+   * the intersection of single bounding planes with the planet itself.
+   */
+  protected final GeoPoint[] edgePoints;
+
+  /** Notable points for minXPlane */
+  protected final GeoPoint[] notableMinXPoints;
+  /** Notable points for maxXPlane */
+  protected final GeoPoint[] notableMaxXPoints;
+  /** Notable points for minYPlane */
+  protected final GeoPoint[] notableMinYPoints;
+  /** Notable points for maxYPlane */
+  protected final GeoPoint[] notableMaxYPoints;
+  /** Notable points for minZPlane */
+  protected final GeoPoint[] notableMinZPoints;
+  /** Notable points for maxZPlane */
+  protected final GeoPoint[] notableMaxZPoints;
+
+  /**
+   * Sole constructor
+   *
+   *@param planetModel is the planet model.
+   *@param minX is the minimum X value.
+   *@param maxX is the maximum X value.
+   *@param minY is the minimum Y value.
+   *@param maxY is the maximum Y value.
+   *@param minZ is the minimum Z value.
+   *@param maxZ is the maximum Z value.
+   */
+  public StandardXYZSolid(final PlanetModel planetModel,
+    final double minX,
+    final double maxX,
+    final double minY,
+    final double maxY,
+    final double minZ,
+    final double maxZ) {
+    super(planetModel);
+    // Argument checking
+    if (maxX - minX < Vector.MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("X values in wrong order or identical");
+    if (maxY - minY < Vector.MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("Y values in wrong order or identical");
+    if (maxZ - minZ < Vector.MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("Z values in wrong order or identical");
+
+    final double worldMinX = planetModel.getMinimumXValue();
+    final double worldMaxX = planetModel.getMaximumXValue();
+    final double worldMinY = planetModel.getMinimumYValue();
+    final double worldMaxY = planetModel.getMaximumYValue();
+    final double worldMinZ = planetModel.getMinimumZValue();
+    final double worldMaxZ = planetModel.getMaximumZValue();
+    
+    // We must distinguish between the case where the solid represents the entire world,
+    // and when the solid has no overlap with any part of the surface.  In both cases,
+    // there will be no edgepoints.
+    isWholeWorld =
+        (minX - worldMinX < -Vector.MINIMUM_RESOLUTION) &&
+        (maxX - worldMaxX > Vector.MINIMUM_RESOLUTION) &&
+        (minY - worldMinY < -Vector.MINIMUM_RESOLUTION) &&
+        (maxY - worldMaxY > Vector.MINIMUM_RESOLUTION) &&
+        (minZ - worldMinZ < -Vector.MINIMUM_RESOLUTION) &&
+        (maxZ - worldMaxZ > Vector.MINIMUM_RESOLUTION);
+
+    if (isWholeWorld) {
+      minXPlane = null;
+      maxXPlane = null;
+      minYPlane = null;
+      maxYPlane = null;
+      minZPlane = null;
+      maxZPlane = null;
+      notableMinXPoints = null;
+      notableMaxXPoints = null;
+      notableMinYPoints = null;
+      notableMaxYPoints = null;
+      notableMinZPoints = null;
+      notableMaxZPoints = null;
+      edgePoints = null;
+    } else {
+      // Construct the planes
+      minXPlane = new SidedPlane(maxX,0.0,0.0,xUnitVector,-minX);
+      maxXPlane = new SidedPlane(minX,0.0,0.0,xUnitVector,-maxX);
+      minYPlane = new SidedPlane(0.0,maxY,0.0,yUnitVector,-minY);
+      maxYPlane = new SidedPlane(0.0,minY,0.0,yUnitVector,-maxY);
+      minZPlane = new SidedPlane(0.0,0.0,maxZ,zUnitVector,-minZ);
+      maxZPlane = new SidedPlane(0.0,0.0,minZ,zUnitVector,-maxZ);
+      
+      // We need at least one point on the planet surface for each manifestation of the shape.
+      // There can be up to 2 (on opposite sides of the world).  But we have to go through
+      // 12 combinations of adjacent planes in order to find out if any have 2 intersection solution.
+      // Typically, this requires 12 square root operations. 
+      final GeoPoint[] minXminY = minXPlane.findIntersections(planetModel,minYPlane,maxXPlane,maxYPlane,minZPlane,maxZPlane);
+      final GeoPoint[] minXmaxY = minXPlane.findIntersections(planetModel,maxYPlane,maxXPlane,minYPlane,minZPlane,maxZPlane);
+      final GeoPoint[] minXminZ = minXPlane.findIntersections(planetModel,minZPlane,maxXPlane,maxZPlane,minYPlane,maxYPlane);
+      final GeoPoint[] minXmaxZ = minXPlane.findIntersections(planetModel,maxZPlane,maxXPlane,minZPlane,minYPlane,maxYPlane);
+
+      final GeoPoint[] maxXminY = maxXPlane.findIntersections(planetModel,minYPlane,minXPlane,maxYPlane,minZPlane,maxZPlane);
+      final GeoPoint[] maxXmaxY = maxXPlane.findIntersections(planetModel,maxYPlane,minXPlane,minYPlane,minZPlane,maxZPlane);
+      final GeoPoint[] maxXminZ = maxXPlane.findIntersections(planetModel,minZPlane,minXPlane,maxZPlane,minYPlane,maxYPlane);
+      final GeoPoint[] maxXmaxZ = maxXPlane.findIntersections(planetModel,maxZPlane,minXPlane,minZPlane,minYPlane,maxYPlane);
+      
+      final GeoPoint[] minYminZ = minYPlane.findIntersections(planetModel,minZPlane,maxYPlane,maxZPlane,minXPlane,maxXPlane);
+      final GeoPoint[] minYmaxZ = minYPlane.findIntersections(planetModel,maxZPlane,maxYPlane,minZPlane,minXPlane,maxXPlane);
+      final GeoPoint[] maxYminZ = maxYPlane.findIntersections(planetModel,minZPlane,minYPlane,maxZPlane,minXPlane,maxXPlane);
+      final GeoPoint[] maxYmaxZ = maxYPlane.findIntersections(planetModel,maxZPlane,minYPlane,minZPlane,minXPlane,maxXPlane);
+      
+      notableMinXPoints = glueTogether(minXminY, minXmaxY, minXminZ, minXmaxZ);
+      notableMaxXPoints = glueTogether(maxXminY, maxXmaxY, maxXminZ, maxXmaxZ);
+      notableMinYPoints = glueTogether(minXminY, maxXminY, minYminZ, minYmaxZ);
+      notableMaxYPoints = glueTogether(minXmaxY, maxXmaxY, maxYminZ, maxYmaxZ);
+      notableMinZPoints = glueTogether(minXminZ, maxXminZ, minYminZ, maxYminZ);
+      notableMaxZPoints = glueTogether(minXmaxZ, maxXmaxZ, minYmaxZ, maxYmaxZ);
+
+      // Now, compute the edge points.
+      // This is the trickiest part of setting up an XYZSolid.  We've computed intersections already, so
+      // we'll start there.
+      // There can be a number of shapes, each of which needs an edgepoint.  Each side by itself might contribute
+      // an edgepoint, for instance, if the plane describing that side intercepts the planet in such a way that the ellipse
+      // of interception does not meet any other planes.  Plane intersections can each contribute 0, 1, or 2 edgepoints.
+      //
+      // All of this makes for a lot of potential edgepoints, but I believe these can be pruned back with careful analysis.
+      // I haven't yet done that analysis, however, so I will treat them all as individual edgepoints.
+      
+      // The cases we are looking for are when the four corner points for any given
+      // plane are all outside of the world, AND that plane intersects the world.
+      // There are eight corner points all told; we must evaluate these WRT the planet surface.
+      final boolean minXminYminZ = planetModel.pointOutside(minX, minY, minZ);
+      final boolean minXminYmaxZ = planetModel.pointOutside(minX, minY, maxZ);
+      final boolean minXmaxYminZ = planetModel.pointOutside(minX, maxY, minZ);
+      final boolean minXmaxYmaxZ = planetModel.pointOutside(minX, maxY, maxZ);
+      final boolean maxXminYminZ = planetModel.pointOutside(maxX, minY, minZ);
+      final boolean maxXminYmaxZ = planetModel.pointOutside(maxX, minY, maxZ);
+      final boolean maxXmaxYminZ = planetModel.pointOutside(maxX, maxY, minZ);
+      final boolean maxXmaxYmaxZ = planetModel.pointOutside(maxX, maxY, maxZ);
+        
+      // Look at single-plane/world intersections.
+      // We detect these by looking at the world model and noting its x, y, and z bounds.
+
+      final GeoPoint[] minXEdges;
+      if (minX - worldMinX >= -Vector.MINIMUM_RESOLUTION && minX - worldMaxX <= Vector.MINIMUM_RESOLUTION &&
+        minY < 0.0 && maxY > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
+        minXminYminZ && minXminYmaxZ && minXmaxYminZ && minXmaxYmaxZ) {
+        // Find any point on the minX plane that intersects the world
+        // First construct a perpendicular plane that will allow us to find a sample point.
+        // This plane is vertical and goes through the points (0,0,0) and (1,0,0)
+        // Then use it to compute a sample point.
+        final GeoPoint intPoint = minXPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
+        if (intPoint != null) {
+          minXEdges = new GeoPoint[]{intPoint};
+        } else {
+          // No intersection found?
+          minXEdges = EMPTY_POINTS;
+        }
+      } else {
+        minXEdges = EMPTY_POINTS;
+      }
+      
+      final GeoPoint[] maxXEdges;
+      if (maxX - worldMinX >= -Vector.MINIMUM_RESOLUTION && maxX - worldMaxX <= Vector.MINIMUM_RESOLUTION &&
+        minY < 0.0 && maxY > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
+        maxXminYminZ && maxXminYmaxZ && maxXmaxYminZ && maxXmaxYmaxZ) {
+        // Find any point on the maxX plane that intersects the world
+        // First construct a perpendicular plane that will allow us to find a sample point.
+        // This plane is vertical and goes through the points (0,0,0) and (1,0,0)
+        // Then use it to compute a sample point.
+        final GeoPoint intPoint = maxXPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
+        if (intPoint != null) {
+          maxXEdges = new GeoPoint[]{intPoint};
+        } else {
+          maxXEdges = EMPTY_POINTS;
+        }
+      } else {
+        maxXEdges = EMPTY_POINTS;
+      }
+      
+      final GeoPoint[] minYEdges;
+      if (minY - worldMinY >= -Vector.MINIMUM_RESOLUTION && minY - worldMaxY <= Vector.MINIMUM_RESOLUTION &&
+        minX < 0.0 && maxX > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
+        minXminYminZ && minXminYmaxZ && maxXminYminZ && maxXminYmaxZ) {
+        // Find any point on the minY plane that intersects the world
+        // First construct a perpendicular plane that will allow us to find a sample point.
+        // This plane is vertical and goes through the points (0,0,0) and (0,1,0)
+        // Then use it to compute a sample point.
+        final GeoPoint intPoint = minYPlane.getSampleIntersectionPoint(planetModel, yVerticalPlane);
+        if (intPoint != null) {
+          minYEdges = new GeoPoint[]{intPoint};
+        } else {
+          minYEdges = EMPTY_POINTS;
+        }
+      } else {
+        minYEdges = EMPTY_POINTS;
+      }
+      
+      final GeoPoint[] maxYEdges;
+      if (maxY - worldMinY >= -Vector.MINIMUM_RESOLUTION && maxY - worldMaxY <= Vector.MINIMUM_RESOLUTION &&
+        minX < 0.0 && maxX > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
+        minXmaxYminZ && minXmaxYmaxZ && maxXmaxYminZ && maxXmaxYmaxZ) {
+        // Find any point on the maxY plane that intersects the world
+        // First construct a perpendicular plane that will allow us to find a sample point.
+        // This plane is vertical and goes through the points (0,0,0) and (0,1,0)
+        // Then use it to compute a sample point.
+        final GeoPoint intPoint = maxYPlane.getSampleIntersectionPoint(planetModel, yVerticalPlane);
+        if (intPoint != null) {
+          maxYEdges = new GeoPoint[]{intPoint};
+        } else {
+          maxYEdges = EMPTY_POINTS;
+        }
+      } else {
+        maxYEdges = EMPTY_POINTS;
+      }
+      
+      final GeoPoint[] minZEdges;
+      if (minZ - worldMinZ >= -Vector.MINIMUM_RESOLUTION && minZ - worldMaxZ <= Vector.MINIMUM_RESOLUTION &&
+        minX < 0.0 && maxX > 0.0 && minY < 0.0 && maxY > 0.0 &&
+        minXminYminZ && minXmaxYminZ && maxXminYminZ && maxXmaxYminZ) {
+        // Find any point on the minZ plane that intersects the world
+        // First construct a perpendicular plane that will allow us to find a sample point.
+        // This plane is vertical and goes through the points (0,0,0) and (1,0,0)
+        // Then use it to compute a sample point.
+        final GeoPoint intPoint = minZPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
+        if (intPoint != null) {
+          minZEdges = new GeoPoint[]{intPoint};
+        } else {
+          minZEdges = EMPTY_POINTS;
+        }
+      } else {
+        minZEdges = EMPTY_POINTS;
+      }
+      
+      final GeoPoint[] maxZEdges;
+      if (maxZ - worldMinZ >= -Vector.MINIMUM_RESOLUTION && maxZ - worldMaxZ <= Vector.MINIMUM_RESOLUTION &&
+        minX < 0.0 && maxX > 0.0 && minY < 0.0 && maxY > 0.0 &&
+        minXminYmaxZ && minXmaxYmaxZ && maxXminYmaxZ && maxXmaxYmaxZ) {
+        // Find any point on the maxZ plane that intersects the world
+        // First construct a perpendicular plane that will allow us to find a sample point.
+        // This plane is vertical and goes through the points (0,0,0) and (1,0,0) (that is, its orientation doesn't matter)
+        // Then use it to compute a sample point.
+        final GeoPoint intPoint = maxZPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
+        if (intPoint != null) {
+          maxZEdges = new GeoPoint[]{intPoint};
+        } else {
+          maxZEdges = EMPTY_POINTS;
+        }
+      } else {
+        maxZEdges = EMPTY_POINTS;
+      }
+      
+      // Glue everything together.  This is not a minimal set of edgepoints, as of now, but it does completely describe all shapes on the
+      // planet.
+      this.edgePoints = glueTogether(minXminY, minXmaxY, minXminZ, minXmaxZ,
+        maxXminY, maxXmaxY, maxXminZ, maxXmaxZ,
+        minYminZ, minYmaxZ, maxYminZ, maxYmaxZ,
+        minXEdges, maxXEdges, minYEdges, maxYEdges, minZEdges, maxZEdges);
+    }
+  }
+
+  @Override
+  protected GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+  
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    if (isWholeWorld) {
+      return true;
+    }
+    return minXPlane.isWithin(x, y, z) &&
+      maxXPlane.isWithin(x, y, z) &&
+      minYPlane.isWithin(x, y, z) &&
+      maxYPlane.isWithin(x, y, z) &&
+      minZPlane.isWithin(x, y, z) &&
+      maxZPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    if (isWholeWorld) {
+      if (path.getEdgePoints().length > 0)
+        return WITHIN;
+      return OVERLAPS;
+    }
+    
+    /*
+    for (GeoPoint p : getEdgePoints()) {
+      System.err.println(" Edge point "+p+" path.isWithin()? "+path.isWithin(p));
+    }
+    
+    for (GeoPoint p : path.getEdgePoints()) {
+      System.err.println(" path edge point "+p+" isWithin()? "+isWithin(p)+" minx="+minXPlane.evaluate(p)+" maxx="+maxXPlane.evaluate(p)+" miny="+minYPlane.evaluate(p)+" maxy="+maxYPlane.evaluate(p)+" minz="+minZPlane.evaluate(p)+" maxz="+maxZPlane.evaluate(p));
+    }
+    */
+    
+    //System.err.println(this+" getrelationship with "+path);
+    final int insideRectangle = isShapeInsideArea(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some shape points inside area");
+      return OVERLAPS;
+    }
+
+    // Figure out if the entire XYZArea is contained by the shape.
+    final int insideShape = isAreaInsideShape(path);
+    if (insideShape == SOME_INSIDE) {
+      //System.err.println(" some area points inside shape");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
+      //System.err.println(" inside of each other");
+      return OVERLAPS;
+    }
+
+    if (path.intersects(minXPlane, notableMinXPoints, maxXPlane, minYPlane, maxYPlane, minZPlane, maxZPlane) ||
+        path.intersects(maxXPlane, notableMaxXPoints, minXPlane, minYPlane, maxYPlane, minZPlane, maxZPlane) ||
+        path.intersects(minYPlane, notableMinYPoints, maxYPlane, minXPlane, maxXPlane, minZPlane, maxZPlane) ||
+        path.intersects(maxYPlane, notableMaxYPoints, minYPlane, minXPlane, maxXPlane, minZPlane, maxZPlane) ||
+        path.intersects(minZPlane, notableMinZPoints, maxZPlane, minXPlane, maxXPlane, minYPlane, maxYPlane) ||
+        path.intersects(maxZPlane, notableMaxZPoints, minZPlane, minXPlane, maxXPlane, minYPlane, maxYPlane)) {
+      //System.err.println(" edges intersect");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      //System.err.println(" all shape points inside area");
+      return WITHIN;
+    }
+
+    if (insideShape == ALL_INSIDE) {
+      //System.err.println(" all area points inside shape");
+      return CONTAINS;
+    }
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof StandardXYZSolid))
+      return false;
+    StandardXYZSolid other = (StandardXYZSolid) o;
+    if (!super.equals(other) ||
+      other.isWholeWorld != isWholeWorld) {
+      return false;
+    }
+    if (!isWholeWorld) {
+      return other.minXPlane.equals(minXPlane) &&
+        other.maxXPlane.equals(maxXPlane) &&
+        other.minYPlane.equals(minYPlane) &&
+        other.maxYPlane.equals(maxYPlane) &&
+        other.minZPlane.equals(minZPlane) &&
+        other.maxZPlane.equals(maxZPlane);
+    }
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result + (isWholeWorld?1:0);
+    if (!isWholeWorld) {
+      result = 31 * result  + minXPlane.hashCode();
+      result = 31 * result  + maxXPlane.hashCode();
+      result = 31 * result  + minYPlane.hashCode();
+      result = 31 * result  + maxYPlane.hashCode();
+      result = 31 * result  + minZPlane.hashCode();
+      result = 31 * result  + maxZPlane.hashCode();
+    }
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "StandardXYZSolid: {planetmodel="+planetModel+", isWholeWorld="+isWholeWorld+", minXplane="+minXPlane+", maxXplane="+maxXPlane+", minYplane="+minYPlane+", maxYplane="+maxYPlane+", minZplane="+minZPlane+", maxZplane="+maxZPlane+"}";
+  }
+  
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Tools.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Tools.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Tools.java
new file mode 100755
index 0000000..e8ee29e
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Tools.java
@@ -0,0 +1,41 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Static methods globally useful for 3d geometric work.
+ *
+ * @lucene.experimental
+ */
+public class Tools {
+  private Tools() {
+  }
+
+  /**
+   * Java acos yields a NAN if you take an arc-cos of an
+   * angle that's just a tiny bit greater than 1.0, so
+   * here's a more resilient version.
+   */
+  public static double safeAcos(double value) {
+    if (value > 1.0)
+      value = 1.0;
+    else if (value < -1.0)
+      value = -1.0;
+    return Math.acos(value);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Vector.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Vector.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Vector.java
new file mode 100755
index 0000000..3a1b233
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Vector.java
@@ -0,0 +1,378 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * A 3d vector in space, not necessarily
+ * going through the origin.
+ *
+ * @lucene.experimental
+ */
+public class Vector {
+  /**
+   * Values that are all considered to be essentially zero have a magnitude
+   * less than this.
+   */
+  public static final double MINIMUM_RESOLUTION = 1.0e-12;
+  /**
+   * For squared quantities, the bound is squared too.
+   */
+  public static final double MINIMUM_RESOLUTION_SQUARED = MINIMUM_RESOLUTION * MINIMUM_RESOLUTION;
+  /**
+   * For cubed quantities, cube the bound.
+   */
+  public static final double MINIMUM_RESOLUTION_CUBED = MINIMUM_RESOLUTION_SQUARED * MINIMUM_RESOLUTION;
+
+  /** The x value */
+  public final double x;
+  /** The y value */
+  public final double y;
+  /** The z value */
+  public final double z;
+
+  /**
+   * Construct from (U.S.) x,y,z coordinates.
+   *@param x is the x value.
+   *@param y is the y value.
+   *@param z is the z value.
+   */
+  public Vector(double x, double y, double z) {
+    this.x = x;
+    this.y = y;
+    this.z = z;
+  }
+
+  /**
+   * Construct a vector that is perpendicular to
+   * two other (non-zero) vectors.  If the vectors are parallel,
+   * IllegalArgumentException will be thrown.
+   * Produces a normalized final vector.
+   *
+   * @param A is the first vector
+   * @param B is the second
+   */
+  public Vector(final Vector A, final Vector B) {
+    // x = u2v3 - u3v2
+    // y = u3v1 - u1v3
+    // z = u1v2 - u2v1
+    final double thisX = A.y * B.z - A.z * B.y;
+    final double thisY = A.z * B.x - A.x * B.z;
+    final double thisZ = A.x * B.y - A.y * B.x;
+    final double magnitude = magnitude(thisX, thisY, thisZ);
+    if (Math.abs(magnitude) < MINIMUM_RESOLUTION) {
+      throw new IllegalArgumentException("Degenerate/parallel vector constructed");
+    }
+    final double inverseMagnitude = 1.0 / magnitude;
+    this.x = thisX * inverseMagnitude;
+    this.y = thisY * inverseMagnitude;
+    this.z = thisZ * inverseMagnitude;
+  }
+
+  /** Compute a magnitude of an x,y,z value.
+   */
+  public static double magnitude(final double x, final double y, final double z) {
+    return Math.sqrt(x*x + y*y + z*z);
+  }
+  
+  /**
+   * Compute a normalized unit vector based on the current vector.
+   *
+   * @return the normalized vector, or null if the current vector has
+   * a magnitude of zero.
+   */
+  public Vector normalize() {
+    double denom = magnitude();
+    if (denom < MINIMUM_RESOLUTION)
+      // Degenerate, can't normalize
+      return null;
+    double normFactor = 1.0 / denom;
+    return new Vector(x * normFactor, y * normFactor, z * normFactor);
+  }
+
+  /**
+   * Do a dot product.
+   *
+   * @param v is the vector to multiply.
+   * @return the result.
+   */
+  public double dotProduct(final Vector v) {
+    return this.x * v.x + this.y * v.y + this.z * v.z;
+  }
+
+  /**
+   * Do a dot product.
+   *
+   * @param x is the x value of the vector to multiply.
+   * @param y is the y value of the vector to multiply.
+   * @param z is the z value of the vector to multiply.
+   * @return the result.
+   */
+  public double dotProduct(final double x, final double y, final double z) {
+    return this.x * x + this.y * y + this.z * z;
+  }
+
+  /**
+   * Determine if this vector, taken from the origin,
+   * describes a point within a set of planes.
+   *
+   * @param bounds     is the first part of the set of planes.
+   * @param moreBounds is the second part of the set of planes.
+   * @return true if the point is within the bounds.
+   */
+  public boolean isWithin(final Membership[] bounds, final Membership[] moreBounds) {
+    // Return true if the point described is within all provided bounds
+    //System.err.println("  checking if "+this+" is within bounds");
+    for (Membership bound : bounds) {
+      if (bound != null && !bound.isWithin(this)) {
+        //System.err.println("    NOT within "+bound);
+        return false;
+      }
+    }
+    for (Membership bound : moreBounds) {
+      if (bound != null && !bound.isWithin(this)) {
+        //System.err.println("    NOT within "+bound);
+        return false;
+      }
+    }
+    //System.err.println("    is within");
+    return true;
+  }
+
+  /**
+   * Translate vector.
+   */
+  public Vector translate(final double xOffset, final double yOffset, final double zOffset) {
+    return new Vector(x - xOffset, y - yOffset, z - zOffset);
+  }
+
+  /**
+   * Rotate vector counter-clockwise in x-y by an angle.
+   */
+  public Vector rotateXY(final double angle) {
+    return rotateXY(Math.sin(angle), Math.cos(angle));
+  }
+
+  /**
+   * Rotate vector counter-clockwise in x-y by an angle, expressed as sin and cos.
+   */
+  public Vector rotateXY(final double sinAngle, final double cosAngle) {
+    return new Vector(x * cosAngle - y * sinAngle, x * sinAngle + y * cosAngle, z);
+  }
+
+  /**
+   * Rotate vector counter-clockwise in x-z by an angle.
+   */
+  public Vector rotateXZ(final double angle) {
+    return rotateXZ(Math.sin(angle), Math.cos(angle));
+  }
+
+  /**
+   * Rotate vector counter-clockwise in x-z by an angle, expressed as sin and cos.
+   */
+  public Vector rotateXZ(final double sinAngle, final double cosAngle) {
+    return new Vector(x * cosAngle - z * sinAngle, y, x * sinAngle + z * cosAngle);
+  }
+
+  /**
+   * Rotate vector counter-clockwise in z-y by an angle.
+   */
+  public Vector rotateZY(final double angle) {
+    return rotateZY(Math.sin(angle), Math.cos(angle));
+  }
+
+  /**
+   * Rotate vector counter-clockwise in z-y by an angle, expressed as sin and cos.
+   */
+  public Vector rotateZY(final double sinAngle, final double cosAngle) {
+    return new Vector(x, z * sinAngle + y * cosAngle, z * cosAngle - y * sinAngle);
+  }
+
+  /**
+   * Compute the square of a straight-line distance to a point described by the
+   * vector taken from the origin.
+   * Monotonically increasing for arc distances up to PI.
+   *
+   * @param v is the vector to compute a distance to.
+   * @return the square of the linear distance.
+   */
+  public double linearDistanceSquared(final Vector v) {
+    double deltaX = this.x - v.x;
+    double deltaY = this.y - v.y;
+    double deltaZ = this.z - v.z;
+    return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
+  }
+
+  /**
+   * Compute the square of a straight-line distance to a point described by the
+   * vector taken from the origin.
+   * Monotonically increasing for arc distances up to PI.
+   *
+   * @param x is the x part of the vector to compute a distance to.
+   * @param y is the y part of the vector to compute a distance to.
+   * @param z is the z part of the vector to compute a distance to.
+   * @return the square of the linear distance.
+   */
+  public double linearDistanceSquared(final double x, final double y, final double z) {
+    double deltaX = this.x - x;
+    double deltaY = this.y - y;
+    double deltaZ = this.z - z;
+    return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
+  }
+
+  /**
+   * Compute the straight-line distance to a point described by the
+   * vector taken from the origin.
+   * Monotonically increasing for arc distances up to PI.
+   *
+   * @param v is the vector to compute a distance to.
+   * @return the linear distance.
+   */
+  public double linearDistance(final Vector v) {
+    return Math.sqrt(linearDistanceSquared(v));
+  }
+
+  /**
+   * Compute the straight-line distance to a point described by the
+   * vector taken from the origin.
+   * Monotonically increasing for arc distances up to PI.
+   *
+   * @param x is the x part of the vector to compute a distance to.
+   * @param y is the y part of the vector to compute a distance to.
+   * @param z is the z part of the vector to compute a distance to.
+   * @return the linear distance.
+   */
+  public double linearDistance(final double x, final double y, final double z) {
+    return Math.sqrt(linearDistanceSquared(x, y, z));
+  }
+
+  /**
+   * Compute the square of the normal distance to a vector described by a
+   * vector taken from the origin.
+   * Monotonically increasing for arc distances up to PI/2.
+   *
+   * @param v is the vector to compute a distance to.
+   * @return the square of the normal distance.
+   */
+  public double normalDistanceSquared(final Vector v) {
+    double t = dotProduct(v);
+    double deltaX = this.x * t - v.x;
+    double deltaY = this.y * t - v.y;
+    double deltaZ = this.z * t - v.z;
+    return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
+  }
+
+  /**
+   * Compute the square of the normal distance to a vector described by a
+   * vector taken from the origin.
+   * Monotonically increasing for arc distances up to PI/2.
+   *
+   * @param x is the x part of the vector to compute a distance to.
+   * @param y is the y part of the vector to compute a distance to.
+   * @param z is the z part of the vector to compute a distance to.
+   * @return the square of the normal distance.
+   */
+  public double normalDistanceSquared(final double x, final double y, final double z) {
+    double t = dotProduct(x, y, z);
+    double deltaX = this.x * t - x;
+    double deltaY = this.y * t - y;
+    double deltaZ = this.z * t - z;
+    return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
+  }
+
+  /**
+   * Compute the normal (perpendicular) distance to a vector described by a
+   * vector taken from the origin.
+   * Monotonically increasing for arc distances up to PI/2.
+   *
+   * @param v is the vector to compute a distance to.
+   * @return the normal distance.
+   */
+  public double normalDistance(final Vector v) {
+    return Math.sqrt(normalDistanceSquared(v));
+  }
+
+  /**
+   * Compute the normal (perpendicular) distance to a vector described by a
+   * vector taken from the origin.
+   * Monotonically increasing for arc distances up to PI/2.
+   *
+   * @param x is the x part of the vector to compute a distance to.
+   * @param y is the y part of the vector to compute a distance to.
+   * @param z is the z part of the vector to compute a distance to.
+   * @return the normal distance.
+   */
+  public double normalDistance(final double x, final double y, final double z) {
+    return Math.sqrt(normalDistanceSquared(x, y, z));
+  }
+
+  /**
+   * Compute the magnitude of this vector.
+   *
+   * @return the magnitude.
+   */
+  public double magnitude() {
+    return magnitude(x,y,z);
+  }
+
+  /** Compute the desired magnitude of a unit vector projected to a given
+   * planet model.
+   * @param planetModel is the planet model.
+   * @param x is the unit vector x value.
+   * @param y is the unit vector y value.
+   * @param z is the unit vector z value.
+   * @return a magnitude value for that (x,y,z) that projects the vector onto the specified ellipsoid.
+   */
+  protected static double computeDesiredEllipsoidMagnitude(final PlanetModel planetModel, final double x, final double y, final double z) {
+    return 1.0 / Math.sqrt(x*x*planetModel.inverseAbSquared + y*y*planetModel.inverseAbSquared + z*z*planetModel.inverseCSquared);
+  }
+
+  /** Compute the desired magnitude of a unit vector projected to a given
+   * planet model.  The unit vector is specified only by a z value.
+   * @param planetModel is the planet model.
+   * @param z is the unit vector z value.
+   * @return a magnitude value for that z value that projects the vector onto the specified ellipsoid.
+   */
+  protected static double computeDesiredEllipsoidMagnitude(final PlanetModel planetModel, final double z) {
+    return 1.0 / Math.sqrt((1.0-z*z)*planetModel.inverseAbSquared + z*z*planetModel.inverseCSquared);
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof Vector))
+      return false;
+    Vector other = (Vector) o;
+    return (other.x == x && other.y == y && other.z == z);
+  }
+
+  @Override
+  public int hashCode() {
+    int result;
+    long temp;
+    temp = Double.doubleToLongBits(x);
+    result = (int) (temp ^ (temp >>> 32));
+    temp = Double.doubleToLongBits(y);
+    result = 31 * result + (int) (temp ^ (temp >>> 32));
+    temp = Double.doubleToLongBits(z);
+    result = 31 * result + (int) (temp ^ (temp >>> 32));
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "[X=" + x + ", Y=" + y + ", Z=" + z + "]";
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYZBounds.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYZBounds.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYZBounds.java
new file mode 100644
index 0000000..c3ee53d
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYZBounds.java
@@ -0,0 +1,267 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * An object for accumulating XYZ bounds information.
+ *
+ * @lucene.experimental
+ */
+public class XYZBounds implements Bounds {
+
+  /** A 'fudge factor', which is added to maximums and subtracted from minimums,
+   * in order to compensate for potential error deltas.  This would not be necessary
+   * except that our 'bounds' is defined as always equaling or exceeding the boundary
+   * of the shape, and we cannot guarantee that without making MINIMUM_RESOLUTION
+   * unacceptably large.
+   */
+  protected static final double FUDGE_FACTOR = Vector.MINIMUM_RESOLUTION * 2.0;
+  
+  /** Minimum x */
+  protected Double minX = null;
+  /** Maximum x */
+  protected Double maxX = null;
+  /** Minimum y */
+  protected Double minY = null;
+  /** Maximum y */
+  protected Double maxY = null;
+  /** Minimum z */
+  protected Double minZ = null;
+  /** Maximum z */
+  protected Double maxZ = null;
+  
+  /** Set to true if no longitude bounds can be stated */
+  protected boolean noLongitudeBound = false;
+  /** Set to true if no top latitude bound can be stated */
+  protected boolean noTopLatitudeBound = false;
+  /** Set to true if no bottom latitude bound can be stated */
+  protected boolean noBottomLatitudeBound = false;
+
+  /** Construct an empty bounds object */
+  public XYZBounds() {
+  }
+
+  // Accessor methods
+  
+  /** Return the minimum X value.
+   *@return minimum X value.
+   */
+  public Double getMinimumX() {
+    return minX;
+  }
+
+  /** Return the maximum X value.
+   *@return maximum X value.
+   */
+  public Double getMaximumX() {
+    return maxX;
+  }
+
+  /** Return the minimum Y value.
+   *@return minimum Y value.
+   */
+  public Double getMinimumY() {
+    return minY;
+  }
+
+  /** Return the maximum Y value.
+   *@return maximum Y value.
+   */
+  public Double getMaximumY() {
+    return maxY;
+  }
+  
+  /** Return the minimum Z value.
+   *@return minimum Z value.
+   */
+  public Double getMinimumZ() {
+    return minZ;
+  }
+
+  /** Return the maximum Z value.
+   *@return maximum Z value.
+   */
+  public Double getMaximumZ() {
+    return maxZ;
+  }
+
+  /** Return true if minX is as small as the planet model allows.
+   *@return true if minX has reached its bound.
+   */
+  public boolean isSmallestMinX(final PlanetModel planetModel) {
+    if (minX == null)
+      return false;
+    return minX - planetModel.getMinimumXValue() < Vector.MINIMUM_RESOLUTION;
+  }
+  
+  /** Return true if maxX is as large as the planet model allows.
+   *@return true if maxX has reached its bound.
+   */
+  public boolean isLargestMaxX(final PlanetModel planetModel) {
+    if (maxX == null)
+      return false;
+    return planetModel.getMaximumXValue() - maxX < Vector.MINIMUM_RESOLUTION;
+  }
+
+  /** Return true if minY is as small as the planet model allows.
+   *@return true if minY has reached its bound.
+   */
+  public boolean isSmallestMinY(final PlanetModel planetModel) {
+    if (minY == null)
+      return false;
+    return minY - planetModel.getMinimumYValue() < Vector.MINIMUM_RESOLUTION;
+  }
+  
+  /** Return true if maxY is as large as the planet model allows.
+   *@return true if maxY has reached its bound.
+   */
+  public boolean isLargestMaxY(final PlanetModel planetModel) {
+    if (maxY == null)
+      return false;
+    return planetModel.getMaximumYValue() - maxY < Vector.MINIMUM_RESOLUTION;
+  }
+  
+  /** Return true if minZ is as small as the planet model allows.
+   *@return true if minZ has reached its bound.
+   */
+  public boolean isSmallestMinZ(final PlanetModel planetModel) {
+    if (minZ == null)
+      return false;
+    return minZ - planetModel.getMinimumZValue() < Vector.MINIMUM_RESOLUTION;
+  }
+  
+  /** Return true if maxZ is as large as the planet model allows.
+   *@return true if maxZ has reached its bound.
+   */
+  public boolean isLargestMaxZ(final PlanetModel planetModel) {
+    if (maxZ == null)
+      return false;
+    return planetModel.getMaximumZValue() - maxZ < Vector.MINIMUM_RESOLUTION;
+  }
+
+  // Modification methods
+  
+  @Override
+  public Bounds addPlane(final PlanetModel planetModel, final Plane plane, final Membership... bounds) {
+    plane.recordBounds(planetModel, this, bounds);
+    return this;
+  }
+
+  /** Add a horizontal plane to the bounds description.
+   * This method should EITHER use the supplied latitude, OR use the supplied
+   * plane, depending on what is most efficient.
+   *@param planetModel is the planet model.
+   *@param latitude is the latitude.
+   *@param horizontalPlane is the plane.
+   *@param bounds are the constraints on the plane.
+   *@return updated Bounds object.
+   */
+  public Bounds addHorizontalPlane(final PlanetModel planetModel,
+    final double latitude,
+    final Plane horizontalPlane,
+    final Membership... bounds) {
+    return addPlane(planetModel, horizontalPlane, bounds);
+  }
+    
+  /** Add a vertical plane to the bounds description.
+   * This method should EITHER use the supplied longitude, OR use the supplied
+   * plane, depending on what is most efficient.
+   *@param planetModel is the planet model.
+   *@param longitude is the longitude.
+   *@param verticalPlane is the plane.
+   *@param bounds are the constraints on the plane.
+   *@return updated Bounds object.
+   */
+  public Bounds addVerticalPlane(final PlanetModel planetModel,
+    final double longitude,
+    final Plane verticalPlane,
+    final Membership... bounds) {
+    return addPlane(planetModel, verticalPlane, bounds);
+  }
+
+  @Override
+  public Bounds addXValue(final GeoPoint point) {
+    final double x = point.x;
+    final double small = x - FUDGE_FACTOR;
+    if (minX == null || minX > small) {
+      minX = new Double(small);
+    }
+    final double large = x + FUDGE_FACTOR;
+    if (maxX == null || maxX < large) {
+      maxX = new Double(large);
+    }
+    return this;
+  }
+
+  @Override
+  public Bounds addYValue(final GeoPoint point) {
+    final double y = point.y;
+    final double small = y - FUDGE_FACTOR;
+    if (minY == null || minY > small) {
+      minY = new Double(small);
+    }
+    final double large = y + FUDGE_FACTOR;
+    if (maxY == null || maxY < large) {
+      maxY = new Double(large);
+    }
+    return this;
+  }
+
+  @Override
+  public Bounds addZValue(final GeoPoint point) {
+    final double z = point.z;
+    final double small = z - FUDGE_FACTOR;
+    if (minZ == null || minZ > small) {
+      minZ = new Double(small);
+    }
+    final double large = z + FUDGE_FACTOR;
+    if (maxZ == null || maxZ < large) {
+      maxZ = new Double(large);
+    }
+    return this;
+  }
+
+  @Override
+  public Bounds addPoint(final GeoPoint point) {
+    return addXValue(point).addYValue(point).addZValue(point);
+  }
+
+  @Override
+  public Bounds isWide() {
+    // No specific thing we need to do.
+    return this;
+  }
+
+  @Override
+  public Bounds noLongitudeBound() {
+    // No specific thing we need to do.
+    return this;
+  }
+
+  @Override
+  public Bounds noTopLatitudeBound() {
+    // No specific thing we need to do.
+    return this;
+  }
+
+  @Override
+  public Bounds noBottomLatitudeBound() {
+    // No specific thing we need to do.
+    return this;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYZSolid.java
new file mode 100644
index 0000000..9298079
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYZSolid.java
@@ -0,0 +1,26 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Interface for a family of 3D rectangles, bounded on six sides by X,Y,Z limits
+ *
+ * @lucene.internal
+ */
+public interface XYZSolid extends GeoArea {
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYZSolidFactory.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYZSolidFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYZSolidFactory.java
new file mode 100644
index 0000000..25ea400
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYZSolidFactory.java
@@ -0,0 +1,67 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * Factory for {@link XYZSolid}.
+ *
+ * @lucene.experimental
+ */
+public class XYZSolidFactory {
+  private XYZSolidFactory() {
+  }
+
+  /**
+   * Create a XYZSolid of the right kind given (x,y,z) bounds.
+   * @param planetModel is the planet model
+   * @param minX is the min X boundary
+   * @param maxX is the max X boundary
+   * @param minY is the min Y boundary
+   * @param maxY is the max Y boundary
+   * @param minZ is the min Z boundary
+   * @param maxZ is the max Z boundary
+   */
+  public static XYZSolid makeXYZSolid(final PlanetModel planetModel, final double minX, final double maxX, final double minY, final double maxY, final double minZ, final double maxZ) {
+    if (Math.abs(maxX - minX) < Vector.MINIMUM_RESOLUTION) {
+      if (Math.abs(maxY - minY) < Vector.MINIMUM_RESOLUTION) {
+        if (Math.abs(maxZ - minZ) < Vector.MINIMUM_RESOLUTION) {
+          return new dXdYdZSolid(planetModel, (minX+maxX) * 0.5, (minY+maxY) * 0.5, minZ);
+        } else {
+          return new dXdYZSolid(planetModel, (minX+maxX) * 0.5, (minY+maxY) * 0.5, minZ, maxZ);
+        }
+      } else {
+        if (Math.abs(maxZ - minZ) < Vector.MINIMUM_RESOLUTION) {
+          return new dXYdZSolid(planetModel, (minX+maxX) * 0.5, minY, maxY, (minZ+maxZ) * 0.5);
+        } else {
+          return new dXYZSolid(planetModel, (minX+maxX) * 0.5, minY, maxY, minZ, maxZ);
+        }
+      }
+    }
+    if (Math.abs(maxY - minY) < Vector.MINIMUM_RESOLUTION) {
+      if (Math.abs(maxZ - minZ) < Vector.MINIMUM_RESOLUTION) {
+        return new XdYdZSolid(planetModel, minX, maxX, (minY+maxY) * 0.5, (minZ+maxZ) * 0.5);
+      } else {
+        return new XdYZSolid(planetModel, minX, maxX, (minY+maxY) * 0.5, minZ, maxZ);
+      }
+    }
+    if (Math.abs(maxZ - minZ) < Vector.MINIMUM_RESOLUTION) {
+      return new XYdZSolid(planetModel, minX, maxX, minY, maxY, (minZ+maxZ) * 0.5);
+    }
+    return new StandardXYZSolid(planetModel, minX, maxX, minY, maxY, minZ, maxZ);
+  }
+  
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYdZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYdZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYdZSolid.java
new file mode 100644
index 0000000..66aac84
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XYdZSolid.java
@@ -0,0 +1,213 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in Z
+ *
+ * @lucene.internal
+ */
+public class XYdZSolid extends BaseXYZSolid {
+
+  /** Min-X plane */
+  protected final SidedPlane minXPlane;
+  /** Max-X plane */
+  protected final SidedPlane maxXPlane;
+  /** Min-Y plane */
+  protected final SidedPlane minYPlane;
+  /** Max-Y plane */
+  protected final SidedPlane maxYPlane;
+  /** Z plane */
+  protected final Plane zPlane;
+  
+  /** These are the edge points of the shape, which are defined to be at least one point on
+   * each surface area boundary.  In the case of a solid, this includes points which represent
+   * the intersection of XYZ bounding planes and the planet, as well as points representing
+   * the intersection of single bounding planes with the planet itself.
+   */
+  protected final GeoPoint[] edgePoints;
+
+  /** Notable points for ZPlane */
+  protected final GeoPoint[] notableZPoints;
+
+  /**
+   * Sole constructor
+   *
+   *@param planetModel is the planet model.
+   *@param minX is the minimum X value.
+   *@param maxX is the maximum X value.
+   *@param minY is the minimum Y value.
+   *@param maxY is the maximum Y value.
+   *@param Z is the Z value.
+   */
+  public XYdZSolid(final PlanetModel planetModel,
+    final double minX,
+    final double maxX,
+    final double minY,
+    final double maxY,
+    final double Z) {
+    super(planetModel);
+    // Argument checking
+    if (maxX - minX < Vector.MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("X values in wrong order or identical");
+    if (maxY - minY < Vector.MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("Y values in wrong order or identical");
+
+    final double worldMinZ = planetModel.getMinimumZValue();
+    final double worldMaxZ = planetModel.getMaximumZValue();
+    
+    // Construct the planes
+    minXPlane = new SidedPlane(maxX,0.0,0.0,xUnitVector,-minX);
+    maxXPlane = new SidedPlane(minX,0.0,0.0,xUnitVector,-maxX);
+    minYPlane = new SidedPlane(0.0,maxY,0.0,yUnitVector,-minY);
+    maxYPlane = new SidedPlane(0.0,minY,0.0,yUnitVector,-maxY);
+    zPlane = new Plane(zUnitVector,-Z);
+      
+    // We need at least one point on the planet surface for each manifestation of the shape.
+    // There can be up to 2 (on opposite sides of the world).  But we have to go through
+    // 4 combinations of adjacent planes in order to find out if any have 2 intersection solution.
+    // Typically, this requires 4 square root operations. 
+    final GeoPoint[] minXZ = minXPlane.findIntersections(planetModel,zPlane,maxXPlane,minYPlane,maxYPlane);
+    final GeoPoint[] maxXZ = maxXPlane.findIntersections(planetModel,zPlane,minXPlane,minYPlane,maxYPlane);
+    final GeoPoint[] minYZ = minYPlane.findIntersections(planetModel,zPlane,maxYPlane,minXPlane,maxXPlane);
+    final GeoPoint[] maxYZ = maxYPlane.findIntersections(planetModel,zPlane,minYPlane,minXPlane,maxXPlane);
+      
+    notableZPoints = glueTogether(minXZ, maxXZ, minYZ, maxYZ);
+
+    // Now, compute the edge points.
+    // This is the trickiest part of setting up an XYZSolid.  We've computed intersections already, so
+    // we'll start there.  We know that at most there will be two disconnected shapes on the planet surface.
+    // But there's also a case where exactly one plane slices through the world, and none of the bounding plane
+    // intersections do.  Thus, if we don't find any of the edge intersection cases, we have to look for that last case.
+      
+    // If we still haven't encountered anything, we need to look at single-plane/world intersections.
+    // We detect these by looking at the world model and noting its x, y, and z bounds.
+    // The cases we are looking for are when the four corner points for any given
+    // plane are all outside of the world, AND that plane intersects the world.
+    // There are four corner points all told; we must evaluate these WRT the planet surface.
+    final boolean minXminYZ = planetModel.pointOutside(minX, minY, Z);
+    final boolean minXmaxYZ = planetModel.pointOutside(minX, maxY, Z);
+    final boolean maxXminYZ = planetModel.pointOutside(maxX, minY, Z);
+    final boolean maxXmaxYZ = planetModel.pointOutside(maxX, maxY, Z);
+
+    final GeoPoint[] zEdges;
+    if (Z - worldMinZ >= -Vector.MINIMUM_RESOLUTION && Z - worldMaxZ <= Vector.MINIMUM_RESOLUTION &&
+      minX < 0.0 && maxX > 0.0 && minY < 0.0 && maxY > 0.0 &&
+      minXminYZ && minXmaxYZ && maxXminYZ && maxXmaxYZ) {
+      // Find any point on the minZ plane that intersects the world
+      // First construct a perpendicular plane that will allow us to find a sample point.
+      // This plane is vertical and goes through the points (0,0,0) and (1,0,0)
+      // Then use it to compute a sample point.
+      final GeoPoint intPoint = zPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
+      if (intPoint != null) {
+        zEdges = new GeoPoint[]{intPoint};
+      } else {
+        zEdges = EMPTY_POINTS;
+      }
+    } else {
+      zEdges= EMPTY_POINTS;
+    }
+
+    this.edgePoints = glueTogether(minXZ, maxXZ, minYZ, maxYZ, zEdges);
+  }
+
+  @Override
+  protected GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+  
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return minXPlane.isWithin(x, y, z) &&
+      maxXPlane.isWithin(x, y, z) &&
+      minYPlane.isWithin(x, y, z) &&
+      maxYPlane.isWithin(x, y, z) &&
+      zPlane.evaluateIsZero(x, y, z);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    
+    //System.err.println(this+" getrelationship with "+path);
+    final int insideRectangle = isShapeInsideArea(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some inside");
+      return OVERLAPS;
+    }
+
+    // Figure out if the entire XYZArea is contained by the shape.
+    final int insideShape = isAreaInsideShape(path);
+    if (insideShape == SOME_INSIDE) {
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
+      //System.err.println(" inside of each other");
+      return OVERLAPS;
+    }
+
+    if (path.intersects(zPlane, notableZPoints, minXPlane, maxXPlane, minYPlane, maxYPlane)) {
+      //System.err.println(" edges intersect");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      //System.err.println(" shape inside rectangle");
+      return WITHIN;
+    }
+
+    if (insideShape == ALL_INSIDE) {
+      //System.err.println(" shape contains rectangle");
+      return CONTAINS;
+    }
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof XYdZSolid))
+      return false;
+    XYdZSolid other = (XYdZSolid) o;
+    if (!super.equals(other)) {
+      return false;
+    }
+    return other.minXPlane.equals(minXPlane) &&
+      other.maxXPlane.equals(maxXPlane) &&
+      other.minYPlane.equals(minYPlane) &&
+      other.maxYPlane.equals(maxYPlane) &&
+      other.zPlane.equals(zPlane);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result  + minXPlane.hashCode();
+    result = 31 * result  + maxXPlane.hashCode();
+    result = 31 * result  + minYPlane.hashCode();
+    result = 31 * result  + maxYPlane.hashCode();
+    result = 31 * result  + zPlane.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "XYdZSolid: {planetmodel="+planetModel+", minXplane="+minXPlane+", maxXplane="+maxXPlane+", minYplane="+minYPlane+", maxYplane="+maxYPlane+", zplane="+zPlane+"}";
+  }
+  
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XdYZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XdYZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XdYZSolid.java
new file mode 100644
index 0000000..d9e11b8
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XdYZSolid.java
@@ -0,0 +1,212 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in Y
+ *
+ * @lucene.internal
+ */
+public class XdYZSolid extends BaseXYZSolid {
+
+  /** Min-X plane */
+  protected final SidedPlane minXPlane;
+  /** Max-X plane */
+  protected final SidedPlane maxXPlane;
+  /** Y plane */
+  protected final Plane yPlane;
+  /** Min-Z plane */
+  protected final SidedPlane minZPlane;
+  /** Max-Z plane */
+  protected final SidedPlane maxZPlane;
+  
+  /** These are the edge points of the shape, which are defined to be at least one point on
+   * each surface area boundary.  In the case of a solid, this includes points which represent
+   * the intersection of XYZ bounding planes and the planet, as well as points representing
+   * the intersection of single bounding planes with the planet itself.
+   */
+  protected final GeoPoint[] edgePoints;
+
+  /** Notable points for YPlane */
+  protected final GeoPoint[] notableYPoints;
+
+  /**
+   * Sole constructor
+   *
+   *@param planetModel is the planet model.
+   *@param minX is the minimum X value.
+   *@param maxX is the maximum X value.
+   *@param Y is the Y value.
+   *@param minZ is the minimum Z value.
+   *@param maxZ is the maximum Z value.
+   */
+  public XdYZSolid(final PlanetModel planetModel,
+    final double minX,
+    final double maxX,
+    final double Y,
+    final double minZ,
+    final double maxZ) {
+    super(planetModel);
+    // Argument checking
+    if (maxX - minX < Vector.MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("X values in wrong order or identical");
+    if (maxZ - minZ < Vector.MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("Z values in wrong order or identical");
+
+    final double worldMinY = planetModel.getMinimumYValue();
+    final double worldMaxY = planetModel.getMaximumYValue();
+    
+    // Construct the planes
+    minXPlane = new SidedPlane(maxX,0.0,0.0,xUnitVector,-minX);
+    maxXPlane = new SidedPlane(minX,0.0,0.0,xUnitVector,-maxX);
+    yPlane = new Plane(yUnitVector,-Y);
+    minZPlane = new SidedPlane(0.0,0.0,maxZ,zUnitVector,-minZ);
+    maxZPlane = new SidedPlane(0.0,0.0,minZ,zUnitVector,-maxZ);
+      
+    // We need at least one point on the planet surface for each manifestation of the shape.
+    // There can be up to 2 (on opposite sides of the world).  But we have to go through
+    // 4 combinations of adjacent planes in order to find out if any have 2 intersection solution.
+    // Typically, this requires 4 square root operations. 
+    final GeoPoint[] minXY = minXPlane.findIntersections(planetModel,yPlane,maxXPlane,minZPlane,maxZPlane);
+    final GeoPoint[] maxXY = maxXPlane.findIntersections(planetModel,yPlane,minXPlane,minZPlane,maxZPlane);
+    final GeoPoint[] YminZ = yPlane.findIntersections(planetModel,minZPlane,maxZPlane,minXPlane,maxXPlane);
+    final GeoPoint[] YmaxZ = yPlane.findIntersections(planetModel,maxZPlane,minZPlane,minXPlane,maxXPlane);
+      
+    notableYPoints = glueTogether(minXY, maxXY, YminZ, YmaxZ);
+
+    // Now, compute the edge points.
+    // This is the trickiest part of setting up an XYZSolid.  We've computed intersections already, so
+    // we'll start there.  We know that at most there will be two disconnected shapes on the planet surface.
+    // But there's also a case where exactly one plane slices through the world, and none of the bounding plane
+    // intersections do.  Thus, if we don't find any of the edge intersection cases, we have to look for that last case.
+      
+    // We need to look at single-plane/world intersections.
+    // We detect these by looking at the world model and noting its x, y, and z bounds.
+    // The cases we are looking for are when the four corner points for any given
+    // plane are all outside of the world, AND that plane intersects the world.
+    // There are four corner points all told; we must evaluate these WRT the planet surface.
+    final boolean minXYminZ = planetModel.pointOutside(minX, Y, minZ);
+    final boolean minXYmaxZ = planetModel.pointOutside(minX, Y, maxZ);
+    final boolean maxXYminZ = planetModel.pointOutside(maxX, Y, minZ);
+    final boolean maxXYmaxZ = planetModel.pointOutside(maxX, Y, maxZ);
+
+    final GeoPoint[] yEdges;
+    if (Y - worldMinY >= -Vector.MINIMUM_RESOLUTION && Y - worldMaxY <= Vector.MINIMUM_RESOLUTION &&
+      minX < 0.0 && maxX > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
+      minXYminZ && minXYmaxZ && maxXYminZ && maxXYmaxZ) {
+      // Find any point on the minY plane that intersects the world
+      // First construct a perpendicular plane that will allow us to find a sample point.
+      // This plane is vertical and goes through the points (0,0,0) and (0,1,0)
+      // Then use it to compute a sample point.
+      final GeoPoint intPoint = yPlane.getSampleIntersectionPoint(planetModel, yVerticalPlane);
+      if (intPoint != null) {
+        yEdges = new GeoPoint[]{intPoint};
+      } else {
+        yEdges = EMPTY_POINTS;
+      }
+    } else {
+      yEdges = EMPTY_POINTS;
+    }
+
+    this.edgePoints = glueTogether(minXY, maxXY, YminZ, YmaxZ, yEdges);
+  }
+
+  @Override
+  protected GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+  
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return minXPlane.isWithin(x, y, z) &&
+      maxXPlane.isWithin(x, y, z) &&
+      yPlane.evaluateIsZero(x, y, z) &&
+      minZPlane.isWithin(x, y, z) &&
+      maxZPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    //System.err.println(this+" getrelationship with "+path);
+    final int insideRectangle = isShapeInsideArea(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some inside");
+      return OVERLAPS;
+    }
+
+    // Figure out if the entire XYZArea is contained by the shape.
+    final int insideShape = isAreaInsideShape(path);
+    if (insideShape == SOME_INSIDE) {
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
+      //System.err.println(" inside of each other");
+      return OVERLAPS;
+    }
+
+    if (path.intersects(yPlane, notableYPoints, minXPlane, maxXPlane, minZPlane, maxZPlane)) {
+      //System.err.println(" edges intersect");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      //System.err.println(" shape inside rectangle");
+      return WITHIN;
+    }
+
+    if (insideShape == ALL_INSIDE) {
+      //System.err.println(" shape contains rectangle");
+      return CONTAINS;
+    }
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof XdYZSolid))
+      return false;
+    XdYZSolid other = (XdYZSolid) o;
+    if (!super.equals(other)) {
+      return false;
+    }
+    return other.minXPlane.equals(minXPlane) &&
+      other.maxXPlane.equals(maxXPlane) &&
+      other.yPlane.equals(yPlane) &&
+      other.minZPlane.equals(minZPlane) &&
+      other.maxZPlane.equals(maxZPlane);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result  + minXPlane.hashCode();
+    result = 31 * result  + maxXPlane.hashCode();
+    result = 31 * result  + yPlane.hashCode();
+    result = 31 * result  + minZPlane.hashCode();
+    result = 31 * result  + maxZPlane.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "XdYZSolid: {planetmodel="+planetModel+", minXplane="+minXPlane+", maxXplane="+maxXPlane+", yplane="+yPlane+", minZplane="+minZPlane+", maxZplane="+maxZPlane+"}";
+  }
+  
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XdYdZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XdYdZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XdYdZSolid.java
new file mode 100644
index 0000000..33d0bea
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/XdYdZSolid.java
@@ -0,0 +1,138 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in Y and Z.
+ * This figure, in fact, represents either zero, one, or two points, so the
+ * actual data stored is minimal.
+ *
+ * @lucene.internal
+ */
+public class XdYdZSolid extends BaseXYZSolid {
+
+  /** The points in this figure on the planet surface; also doubles for edge points */
+  protected final GeoPoint[] surfacePoints;
+  
+  /**
+   * Sole constructor
+   *
+   *@param planetModel is the planet model.
+   *@param minX is the minimum X value.
+   *@param maxX is the maximum X value.
+   *@param Y is the Y value.
+   *@param Z is the Z value.
+   */
+  public XdYdZSolid(final PlanetModel planetModel,
+    final double minX,
+    final double maxX,
+    final double Y,
+    final double Z) {
+    super(planetModel);
+    // Argument checking
+    if (maxX - minX < Vector.MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("X values in wrong order or identical");
+
+    // Build the planes and intersect them.
+    final Plane yPlane = new Plane(yUnitVector,-Y);
+    final Plane zPlane = new Plane(zUnitVector,-Z);
+    final SidedPlane minXPlane = new SidedPlane(maxX,0.0,0.0,xUnitVector,-minX);
+    final SidedPlane maxXPlane = new SidedPlane(minX,0.0,0.0,xUnitVector,-maxX);
+    surfacePoints = yPlane.findIntersections(planetModel,zPlane,minXPlane,maxXPlane);
+  }
+
+  @Override
+  protected GeoPoint[] getEdgePoints() {
+    return surfacePoints;
+  }
+  
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    for (final GeoPoint p : surfacePoints) {
+      if (p.isIdentical(x,y,z))
+        return true;
+    }
+    return false;
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    //System.err.println(this+" getrelationship with "+path);
+    final int insideRectangle = isShapeInsideArea(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some inside");
+      return OVERLAPS;
+    }
+
+    // Figure out if the entire XYZArea is contained by the shape.
+    final int insideShape = isAreaInsideShape(path);
+    if (insideShape == SOME_INSIDE) {
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
+      //System.err.println(" inside of each other");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      return WITHIN;
+    }
+    
+    if (insideShape == ALL_INSIDE) {
+      //System.err.println(" shape contains rectangle");
+      return CONTAINS;
+    }
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof XdYdZSolid))
+      return false;
+    XdYdZSolid other = (XdYdZSolid) o;
+    if (!super.equals(other) || surfacePoints.length != other.surfacePoints.length ) {
+      return false;
+    }
+    for (int i = 0; i < surfacePoints.length; i++) {
+      if (!surfacePoints[i].equals(other.surfacePoints[i]))
+        return false;
+    }
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    for (final GeoPoint p : surfacePoints) {
+      result = 31 * result  + p.hashCode();
+    }
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    final StringBuilder sb = new StringBuilder();
+    for (final GeoPoint p : surfacePoints) {
+      sb.append(" ").append(p).append(" ");
+    }
+    return "XdYdZSolid: {planetmodel="+planetModel+", "+sb.toString()+"}";
+  }
+  
+}
+  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXYZSolid.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXYZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXYZSolid.java
new file mode 100644
index 0000000..48fe714
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/dXYZSolid.java
@@ -0,0 +1,216 @@
+/*
+ * 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.spatial3d.geom;
+
+/**
+ * 3D rectangle, bounded on six sides by X,Y,Z limits, degenerate in X.
+ *
+ * @lucene.internal
+ */
+public class dXYZSolid extends BaseXYZSolid {
+
+  /** X plane */
+  protected final Plane xPlane;
+  /** Min-Y plane */
+  protected final SidedPlane minYPlane;
+  /** Max-Y plane */
+  protected final SidedPlane maxYPlane;
+  /** Min-Z plane */
+  protected final SidedPlane minZPlane;
+  /** Max-Z plane */
+  protected final SidedPlane maxZPlane;
+  
+  /** These are the edge points of the shape, which are defined to be at least one point on
+   * each surface area boundary.  In the case of a solid, this includes points which represent
+   * the intersection of XYZ bounding planes and the planet, as well as points representing
+   * the intersection of single bounding planes with the planet itself.
+   */
+  protected final GeoPoint[] edgePoints;
+
+  /** Notable points for XPlane */
+  protected final GeoPoint[] notableXPoints;
+
+  /**
+   * Sole constructor
+   *
+   *@param planetModel is the planet model.
+   *@param X is the X value.
+   *@param minY is the minimum Y value.
+   *@param maxY is the maximum Y value.
+   *@param minZ is the minimum Z value.
+   *@param maxZ is the maximum Z value.
+   */
+  public dXYZSolid(final PlanetModel planetModel,
+    final double X,
+    final double minY,
+    final double maxY,
+    final double minZ,
+    final double maxZ) {
+    super(planetModel);
+    // Argument checking
+    if (maxY - minY < Vector.MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("Y values in wrong order or identical");
+    if (maxZ - minZ < Vector.MINIMUM_RESOLUTION)
+      throw new IllegalArgumentException("Z values in wrong order or identical");
+
+    final double worldMinX = planetModel.getMinimumXValue();
+    final double worldMaxX = planetModel.getMaximumXValue();
+    
+    // Construct the planes
+    xPlane = new Plane(xUnitVector,-X);
+    minYPlane = new SidedPlane(0.0,maxY,0.0,yUnitVector,-minY);
+    maxYPlane = new SidedPlane(0.0,minY,0.0,yUnitVector,-maxY);
+    minZPlane = new SidedPlane(0.0,0.0,maxZ,zUnitVector,-minZ);
+    maxZPlane = new SidedPlane(0.0,0.0,minZ,zUnitVector,-maxZ);
+      
+    // We need at least one point on the planet surface for each manifestation of the shape.
+    // There can be up to 2 (on opposite sides of the world).  But we have to go through
+    // 4 combinations of adjacent planes in order to find out if any have 2 intersection solution.
+    // Typically, this requires 4 square root operations. 
+    final GeoPoint[] XminY = xPlane.findIntersections(planetModel,minYPlane,maxYPlane,minZPlane,maxZPlane);
+    final GeoPoint[] XmaxY = xPlane.findIntersections(planetModel,maxYPlane,minYPlane,minZPlane,maxZPlane);
+    final GeoPoint[] XminZ = xPlane.findIntersections(planetModel,minZPlane,maxZPlane,minYPlane,maxYPlane);
+    final GeoPoint[] XmaxZ = xPlane.findIntersections(planetModel,maxZPlane,minZPlane,minYPlane,maxYPlane);
+
+    notableXPoints = glueTogether(XminY, XmaxY, XminZ, XmaxZ);
+
+    // Now, compute the edge points.
+    // This is the trickiest part of setting up an XYZSolid.  We've computed intersections already, so
+    // we'll start there.  We know that at most there will be two disconnected shapes on the planet surface.
+    // But there's also a case where exactly one plane slices through the world, and none of the bounding plane
+    // intersections do.  Thus, if we don't find any of the edge intersection cases, we have to look for that last case.
+      
+    // We need to look at single-plane/world intersections.
+    // We detect these by looking at the world model and noting its x, y, and z bounds.
+    // For the single-dimension degenerate case, there's really only one plane that can possibly intersect the world.
+    // The cases we are looking for are when the four corner points for any given
+    // plane are all outside of the world, AND that plane intersects the world.
+    // There are four corner points all told; we must evaluate these WRT the planet surface.
+    final boolean XminYminZ = planetModel.pointOutside(X, minY, minZ);
+    final boolean XminYmaxZ = planetModel.pointOutside(X, minY, maxZ);
+    final boolean XmaxYminZ = planetModel.pointOutside(X, maxY, minZ);
+    final boolean XmaxYmaxZ = planetModel.pointOutside(X, maxY, maxZ);
+
+    final GeoPoint[] xEdges;
+    if (X - worldMinX >= -Vector.MINIMUM_RESOLUTION && X - worldMaxX <= Vector.MINIMUM_RESOLUTION &&
+      minY < 0.0 && maxY > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
+      XminYminZ && XminYmaxZ && XmaxYminZ && XmaxYmaxZ) {
+      // Find any point on the X plane that intersects the world
+      // First construct a perpendicular plane that will allow us to find a sample point.
+      // This plane is vertical and goes through the points (0,0,0) and (1,0,0)
+      // Then use it to compute a sample point.
+      final GeoPoint intPoint = xPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
+      if (intPoint != null) {
+        xEdges = new GeoPoint[]{intPoint};
+      } else {
+        xEdges = EMPTY_POINTS;
+      }
+    } else {
+      xEdges = EMPTY_POINTS;
+    }
+
+    this.edgePoints = glueTogether(XminY,XmaxY,XminZ,XmaxZ,xEdges);
+  }
+
+  @Override
+  protected GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+  
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return xPlane.evaluateIsZero(x, y, z) &&
+      minYPlane.isWithin(x, y, z) &&
+      maxYPlane.isWithin(x, y, z) &&
+      minZPlane.isWithin(x, y, z) &&
+      maxZPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    //System.err.println(this+" getrelationship with "+path);
+    final int insideRectangle = isShapeInsideArea(path);
+    if (insideRectangle == SOME_INSIDE) {
+      //System.err.println(" some shape points inside area");
+      return OVERLAPS;
+    }
+
+    // Figure out if the entire XYZArea is contained by the shape.
+    final int insideShape = isAreaInsideShape(path);
+    if (insideShape == SOME_INSIDE) {
+      //System.err.println(" some area points inside shape");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
+      //System.err.println(" inside of each other");
+      return OVERLAPS;
+    }
+
+    // The entire locus of points in this shape is on a single plane, so we only need ot look for an intersection with that plane.
+    //System.err.println("xPlane = "+xPlane);
+    if (path.intersects(xPlane, notableXPoints, minYPlane, maxYPlane, minZPlane, maxZPlane)) {
+      //System.err.println(" edges intersect");
+      return OVERLAPS;
+    }
+
+    if (insideRectangle == ALL_INSIDE) {
+      //System.err.println(" shape points inside area");
+      return WITHIN;
+    }
+
+    if (insideShape == ALL_INSIDE) {
+      //System.err.println(" shape contains all area");
+      return CONTAINS;
+    }
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof dXYZSolid))
+      return false;
+    dXYZSolid other = (dXYZSolid) o;
+    if (!super.equals(other)) {
+      return false;
+    }
+    return other.xPlane.equals(xPlane) &&
+      other.minYPlane.equals(minYPlane) &&
+      other.maxYPlane.equals(maxYPlane) &&
+      other.minZPlane.equals(minZPlane) &&
+      other.maxZPlane.equals(maxZPlane);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = super.hashCode();
+    result = 31 * result  + xPlane.hashCode();
+    result = 31 * result  + minYPlane.hashCode();
+    result = 31 * result  + maxYPlane.hashCode();
+    result = 31 * result  + minZPlane.hashCode();
+    result = 31 * result  + maxZPlane.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "dXYZSolid: {planetmodel="+planetModel+", xplane="+xPlane+", minYplane="+minYPlane+", maxYplane="+maxYPlane+", minZplane="+minZPlane+", maxZplane="+maxZPlane+"}";
+  }
+  
+}
+  


[15/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 0093e26)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoConvexPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoConvexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoConvexPolygon.java
deleted file mode 100755
index fc07c4b..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoConvexPolygon.java
+++ /dev/null
@@ -1,288 +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.geo3d;
-
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.List;
-
-/**
- * GeoConvexPolygon objects are generic building blocks of more complex structures.
- * The only restrictions on these objects are: (1) they must be convex; (2) they must have
- * a maximum extent no larger than PI.  Violating either one of these limits will
- * cause the logic to fail.
- *
- * @lucene.experimental
- */
-public class GeoConvexPolygon extends GeoBasePolygon {
-  /** The list of polygon points */
-  protected final List<GeoPoint> points;
-  /** A bitset describing, for each edge, whether it is internal or not */
-  protected final BitSet isInternalEdges;
-
-  /** A list of edges */
-  protected SidedPlane[] edges = null;
-  /** The set of notable points for each edge */
-  protected GeoPoint[][] notableEdgePoints = null;
-  /** A point which is on the boundary of the polygon */
-  protected GeoPoint[] edgePoints = null;
-  /** Tracking the maximum distance we go at any one time, so to be sure it's legal */
-  protected double fullDistance = 0.0;
-  /** Set to true when the polygon is complete */
-  protected boolean isDone = false;
-  
-  /**
-   * Create a convex polygon from a list of points.  The first point must be on the
-   * external edge.
-   *@param planetModel is the planet model.
-   *@param pointList is the list of points to create the polygon from.
-   */
-  public GeoConvexPolygon(final PlanetModel planetModel, final List<GeoPoint> pointList) {
-    super(planetModel);
-    this.points = pointList;
-    this.isInternalEdges = new BitSet();
-    done(false);
-  }
-
-  /**
-   * Create a convex polygon from a list of points, keeping track of which boundaries
-   * are internal.  This is used when creating a polygon as a building block for another shape.
-   *@param planetModel is the planet model.
-   *@param pointList is the set of points to create the polygon from.
-   *@param internalEdgeFlags is a bitset describing whether each edge is internal or not.
-   *@param returnEdgeInternal is true when the final return edge is an internal one.
-   */
-  public GeoConvexPolygon(final PlanetModel planetModel, final List<GeoPoint> pointList, final BitSet internalEdgeFlags,
-                          final boolean returnEdgeInternal) {
-    super(planetModel);
-    this.points = pointList;
-    this.isInternalEdges = internalEdgeFlags;
-    done(returnEdgeInternal);
-  }
-
-  /**
-   * Create a convex polygon, with a starting latitude and longitude.
-   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
-   *@param planetModel is the planet model.
-   *@param startLatitude is the latitude of the first point.
-   *@param startLongitude is the longitude of the first point.
-   */
-  public GeoConvexPolygon(final PlanetModel planetModel, final double startLatitude, final double startLongitude) {
-    super(planetModel);
-    points = new ArrayList<>();
-    isInternalEdges = new BitSet();
-    points.add(new GeoPoint(planetModel, startLatitude, startLongitude));
-  }
-
-  /**
-   * Add a point to the polygon.
-   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
-   *
-   * @param latitude       is the latitude of the next point.
-   * @param longitude      is the longitude of the next point.
-   * @param isInternalEdge is true if the edge just added with this point should be considered "internal", and not
-   *                       intersected as part of the intersects() operation.
-   */
-  public void addPoint(final double latitude, final double longitude, final boolean isInternalEdge) {
-    if (isDone)
-      throw new IllegalStateException("Can't call addPoint() if done() already called");
-    if (isInternalEdge)
-      isInternalEdges.set(points.size() - 1);
-    points.add(new GeoPoint(planetModel, latitude, longitude));
-  }
-
-  /**
-   * Finish the polygon, by connecting the last added point with the starting point.
-   *@param isInternalReturnEdge is true if the return edge (back to start) is an internal one.
-   */
-  public void done(final boolean isInternalReturnEdge) {
-    if (isDone)
-      throw new IllegalStateException("Can't call done() more than once");
-    // If fewer than 3 points, can't do it.
-    if (points.size() < 3)
-      throw new IllegalArgumentException("Polygon needs at least three points.");
-
-    if (isInternalReturnEdge)
-      isInternalEdges.set(points.size() - 1);
-
-    isDone = true;
-    
-    // Time to construct the planes.  If the polygon is truly convex, then any adjacent point
-    // to a segment can provide an interior measurement.
-    edges = new SidedPlane[points.size()];
-    notableEdgePoints = new GeoPoint[points.size()][];
-
-    for (int i = 0; i < points.size(); i++) {
-      final GeoPoint start = points.get(i);
-      final GeoPoint end = points.get(legalIndex(i + 1));
-      final double distance = start.arcDistance(end);
-      if (distance > fullDistance)
-        fullDistance = distance;
-      final GeoPoint check = points.get(legalIndex(i + 2));
-      final SidedPlane sp = new SidedPlane(check, start, end);
-      //System.out.println("Created edge "+sp+" using start="+start+" end="+end+" check="+check);
-      edges[i] = sp;
-      notableEdgePoints[i] = new GeoPoint[]{start, end};
-    }
-    createCenterPoint();
-  }
-
-  /** Compute a reasonable center point.
-   */
-  protected void createCenterPoint() {
-    // In order to naively confirm that the polygon is convex, I would need to
-    // check every edge, and verify that every point (other than the edge endpoints)
-    // is within the edge's sided plane.  This is an order n^2 operation.  That's still
-    // not wrong, though, because everything else about polygons has a similar cost.
-    for (int edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
-      final SidedPlane edge = edges[edgeIndex];
-      for (int pointIndex = 0; pointIndex < points.size(); pointIndex++) {
-        if (pointIndex != edgeIndex && pointIndex != legalIndex(edgeIndex + 1)) {
-          if (!edge.isWithin(points.get(pointIndex)))
-            throw new IllegalArgumentException("Polygon is not convex: Point " + points.get(pointIndex) + " Edge " + edge);
-        }
-      }
-    }
-    edgePoints = new GeoPoint[]{points.get(0)};
-  }
-
-  /** Compute a legal point index from a possibly illegal one, that may have wrapped.
-   *@param index is the index.
-   *@return the normalized index.
-   */
-  protected int legalIndex(int index) {
-    while (index >= points.size())
-      index -= points.size();
-    return index;
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    for (final SidedPlane edge : edges) {
-      if (!edge.isWithin(x, y, z))
-        return false;
-    }
-    return true;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    //System.err.println("Checking for polygon intersection with plane "+p+"...");
-    for (int edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
-      final SidedPlane edge = edges[edgeIndex];
-      final GeoPoint[] points = this.notableEdgePoints[edgeIndex];
-      if (!isInternalEdges.get(edgeIndex)) {
-        //System.err.println(" non-internal edge "+edge);
-        // Edges flagged as 'internal only' are excluded from the matching
-        // Construct boundaries
-        final Membership[] membershipBounds = new Membership[edges.length - 1];
-        int count = 0;
-        for (int otherIndex = 0; otherIndex < edges.length; otherIndex++) {
-          if (otherIndex != edgeIndex) {
-            membershipBounds[count++] = edges[otherIndex];
-          }
-        }
-        if (edge.intersects(planetModel, p, notablePoints, points, bounds, membershipBounds)) {
-          //System.err.println(" intersects!");
-          return true;
-        }
-      }
-    }
-    //System.err.println(" no intersection");
-    return false;
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-
-    // Add all the points
-    for (final GeoPoint point : points) {
-      bounds.addPoint(point);
-    }
-
-    // Add planes with membership.
-    for (int edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
-      final SidedPlane edge = edges[edgeIndex];
-      // Construct boundaries
-      final Membership[] membershipBounds = new Membership[edges.length - 1];
-      int count = 0;
-      for (int otherIndex = 0; otherIndex < edges.length; otherIndex++) {
-        if (otherIndex != edgeIndex) {
-          membershipBounds[count++] = edges[otherIndex];
-        }
-      }
-      bounds.addPlane(planetModel, edge, membershipBounds);
-    }
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    double minimumDistance = Double.MAX_VALUE;
-    for (final GeoPoint edgePoint : points) {
-      final double newDist = distanceStyle.computeDistance(edgePoint, x,y,z);
-      if (newDist < minimumDistance) {
-        minimumDistance = newDist;
-      }
-    }
-    for (int edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
-      final Plane edgePlane = edges[edgeIndex];
-      final Membership[] membershipBounds = new Membership[edges.length - 1];
-      int count = 0;
-      for (int otherIndex = 0; otherIndex < edges.length; otherIndex++) {
-        if (otherIndex != edgeIndex) {
-          membershipBounds[count++] = edges[otherIndex];
-        }
-      }
-      final double newDist = distanceStyle.computeDistance(planetModel, edgePlane, x, y, z, membershipBounds);
-      if (newDist < minimumDistance) {
-        minimumDistance = newDist;
-      }
-    }
-    return minimumDistance;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoConvexPolygon))
-      return false;
-    GeoConvexPolygon other = (GeoConvexPolygon) o;
-    if (!super.equals(other))
-      return false;
-    if (!other.isInternalEdges.equals(isInternalEdges))
-      return false;
-    return (other.points.equals(points));
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + points.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoConvexPolygon: {planetmodel=" + planetModel + ", points=" + points + "}";
-  }
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateHorizontalLine.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateHorizontalLine.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateHorizontalLine.java
deleted file mode 100644
index 6644f0d..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateHorizontalLine.java
+++ /dev/null
@@ -1,215 +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.geo3d;
-
-/**
- * Degenerate bounding box limited on two sides (left lon, right lon).
- * The left-right maximum extent for this shape is PI; for anything larger, use
- * GeoWideDegenerateHorizontalLine.
- *
- * @lucene.internal
- */
-public class GeoDegenerateHorizontalLine extends GeoBaseBBox {
-  /** Latitude of horizontal line */
-  protected final double latitude;
-  /** Left bounding longitude of line */
-  protected final double leftLon;
-  /** Right bounding longitude of line */
-  protected final double rightLon;
-
-  /** Left hand endpoint of line */
-  protected final GeoPoint LHC;
-  /** Right hand endpoint of line */
-  protected final GeoPoint RHC;
-
-  /** The plane describing the line */
-  protected final Plane plane;
-  /** The left side end plane */
-  protected final SidedPlane leftPlane;
-  /** The right side end plane */
-  protected final SidedPlane rightPlane;
-
-  /** Notable points for the line */
-  protected final GeoPoint[] planePoints;
-
-  /** Center of line */
-  protected final GeoPoint centerPoint;
-  /** A point that's on the line */
-  protected final GeoPoint[] edgePoints;
-
-  /**
-   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
-   *@param planetModel is the planet model.
-   *@param latitude is the latitude of the line.
-   *@param leftLon is the left end longitude.
-   *@param rightLon is the right end longitude.
-   */
-  public GeoDegenerateHorizontalLine(final PlanetModel planetModel, final double latitude, final double leftLon, double rightLon) {
-    super(planetModel);
-    // Argument checking
-    if (latitude > Math.PI * 0.5 || latitude < -Math.PI * 0.5)
-      throw new IllegalArgumentException("Latitude out of range");
-    if (leftLon < -Math.PI || leftLon > Math.PI)
-      throw new IllegalArgumentException("Left longitude out of range");
-    if (rightLon < -Math.PI || rightLon > Math.PI)
-      throw new IllegalArgumentException("Right longitude out of range");
-    double extent = rightLon - leftLon;
-    if (extent < 0.0) {
-      extent += 2.0 * Math.PI;
-    }
-    if (extent > Math.PI)
-      throw new IllegalArgumentException("Width of rectangle too great");
-
-    this.latitude = latitude;
-    this.leftLon = leftLon;
-    this.rightLon = rightLon;
-
-    final double sinLatitude = Math.sin(latitude);
-    final double cosLatitude = Math.cos(latitude);
-    final double sinLeftLon = Math.sin(leftLon);
-    final double cosLeftLon = Math.cos(leftLon);
-    final double sinRightLon = Math.sin(rightLon);
-    final double cosRightLon = Math.cos(rightLon);
-
-    // Now build the two points
-    this.LHC = new GeoPoint(planetModel, sinLatitude, sinLeftLon, cosLatitude, cosLeftLon, latitude, leftLon);
-    this.RHC = new GeoPoint(planetModel, sinLatitude, sinRightLon, cosLatitude, cosRightLon, latitude, rightLon);
-
-    this.plane = new Plane(planetModel, sinLatitude);
-
-    // Normalize
-    while (leftLon > rightLon) {
-      rightLon += Math.PI * 2.0;
-    }
-    final double middleLon = (leftLon + rightLon) * 0.5;
-    final double sinMiddleLon = Math.sin(middleLon);
-    final double cosMiddleLon = Math.cos(middleLon);
-
-    this.centerPoint = new GeoPoint(planetModel, sinLatitude, sinMiddleLon, cosLatitude, cosMiddleLon);
-    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
-    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
-
-    this.planePoints = new GeoPoint[]{LHC, RHC};
-
-    this.edgePoints = new GeoPoint[]{centerPoint};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    double newTopLat = latitude + angle;
-    double newBottomLat = latitude - angle;
-    // Figuring out when we escalate to a special case requires some prefiguring
-    double currentLonSpan = rightLon - leftLon;
-    if (currentLonSpan < 0.0)
-      currentLonSpan += Math.PI * 2.0;
-    double newLeftLon = leftLon - angle;
-    double newRightLon = rightLon + angle;
-    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
-      newLeftLon = -Math.PI;
-      newRightLon = Math.PI;
-    }
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return plane.evaluateIsZero(x, y, z) &&
-        leftPlane.isWithin(x, y, z) &&
-        rightPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public double getRadius() {
-    double topAngle = centerPoint.arcDistance(RHC);
-    double bottomAngle = centerPoint.arcDistance(LHC);
-    return Math.max(topAngle, bottomAngle);
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    return centerPoint;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    return p.intersects(planetModel, plane, notablePoints, planePoints, bounds, leftPlane, rightPlane);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds.addHorizontalPlane(planetModel, latitude, plane, leftPlane, rightPlane)
-      .addPoint(LHC).addPoint(RHC);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    //System.err.println("getting relationship between "+this+" and "+path);
-    if (path.intersects(plane, planePoints, leftPlane, rightPlane)) {
-      //System.err.println(" overlaps");
-      return OVERLAPS;
-    }
-
-    if (path.isWithin(centerPoint)) {
-      //System.err.println(" contains");
-      return CONTAINS;
-    }
-
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    final double distance = distanceStyle.computeDistance(planetModel, plane, x,y,z, leftPlane, rightPlane);
-    
-    final double LHCDistance = distanceStyle.computeDistance(LHC, x,y,z);
-    final double RHCDistance = distanceStyle.computeDistance(RHC, x,y,z);
-    
-    return Math.min(
-      distance,
-      Math.min(LHCDistance, RHCDistance));
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoDegenerateHorizontalLine))
-      return false;
-    GeoDegenerateHorizontalLine other = (GeoDegenerateHorizontalLine) o;
-    return super.equals(other) && other.LHC.equals(LHC) && other.RHC.equals(RHC);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + LHC.hashCode();
-    result = 31 * result + RHC.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoDegenerateHorizontalLine: {planetmodel="+planetModel+", latitude=" + latitude + "(" + latitude * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightLon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
-  }
-}
-  
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateLatitudeZone.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateLatitudeZone.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateLatitudeZone.java
deleted file mode 100644
index 4890733..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateLatitudeZone.java
+++ /dev/null
@@ -1,138 +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.geo3d;
-
-/**
- * This GeoBBox represents an area rectangle of one specific latitude with
- * no longitude bounds.
- *
- * @lucene.internal
- */
-public class GeoDegenerateLatitudeZone extends GeoBaseBBox {
-  /** The latitude */
-  protected final double latitude;
-  /** Sine of the latitude */
-  protected final double sinLatitude;
-  /** Plane describing the latitude zone */
-  protected final Plane plane;
-  /** A point on the world that's also on the zone */
-  protected final GeoPoint interiorPoint;
-  /** An array consisting of the interiorPoint */
-  protected final GeoPoint[] edgePoints;
-  /** No notable points */
-  protected final static GeoPoint[] planePoints = new GeoPoint[0];
-
-  /** Constructor.
-   *@param planetModel is the planet model to use.
-   *@param latitude is the latitude of the latitude zone.
-   */
-  public GeoDegenerateLatitudeZone(final PlanetModel planetModel, final double latitude) {
-    super(planetModel);
-    this.latitude = latitude;
-
-    this.sinLatitude = Math.sin(latitude);
-    double cosLatitude = Math.cos(latitude);
-    this.plane = new Plane(planetModel, sinLatitude);
-    // Compute an interior point.
-    interiorPoint = new GeoPoint(planetModel, sinLatitude, 0.0, cosLatitude, 1.0);
-    edgePoints = new GeoPoint[]{interiorPoint};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    double newTopLat = latitude + angle;
-    double newBottomLat = latitude - angle;
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, -Math.PI, Math.PI);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return Math.abs(z - this.sinLatitude) < 1e-10;
-  }
-
-  @Override
-  public double getRadius() {
-    return Math.PI;
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    // Totally arbitrary
-    return interiorPoint;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    return p.intersects(planetModel, plane, notablePoints, planePoints, bounds);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds.noLongitudeBound()
-      .addHorizontalPlane(planetModel, latitude, plane);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    // Second, the shortcut of seeing whether endpoints are in/out is not going to
-    // work with no area endpoints.  So we rely entirely on intersections.
-    //System.out.println("Got here! latitude="+latitude+" path="+path);
-
-    if (path.intersects(plane, planePoints)) {
-      return OVERLAPS;
-    }
-
-    if (path.isWithin(interiorPoint)) {
-      return CONTAINS;
-    }
-
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    return distanceStyle.computeDistance(planetModel, plane, x,y,z);
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoDegenerateLatitudeZone))
-      return false;
-    GeoDegenerateLatitudeZone other = (GeoDegenerateLatitudeZone) o;
-    return super.equals(other) && other.latitude == latitude;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    long temp = Double.doubleToLongBits(latitude);
-    result = 31 * result + (int) (temp ^ (temp >>> 32));
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoDegenerateLatitudeZone: {planetmodel="+planetModel+", lat=" + latitude + "(" + latitude * 180.0 / Math.PI + ")}";
-  }
-}
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateLongitudeSlice.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateLongitudeSlice.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateLongitudeSlice.java
deleted file mode 100644
index b5eb902..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateLongitudeSlice.java
+++ /dev/null
@@ -1,153 +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.geo3d;
-
-/**
- * Degenerate longitude slice.
- *
- * @lucene.internal
- */
-public class GeoDegenerateLongitudeSlice extends GeoBaseBBox {
-  /** The longitude of the slice */
-  protected final double longitude;
-
-  /** The bounding plane for the slice (through both poles, perpendicular to the slice) */
-  protected final SidedPlane boundingPlane;
-  /** The plane of the slice */
-  protected final Plane plane;
-  /** A point on the slice */
-  protected final GeoPoint interiorPoint;
-  /** An array consisting of the one point chosen on the slice */
-  protected final GeoPoint[] edgePoints;
-  /** Notable points for the slice (north and south poles) */
-  protected final GeoPoint[] planePoints;
-
-  /**
-   * Accepts only values in the following ranges: lon: {@code -PI -> PI}
-   */
-  public GeoDegenerateLongitudeSlice(final PlanetModel planetModel, final double longitude) {
-    super(planetModel);
-    // Argument checking
-    if (longitude < -Math.PI || longitude > Math.PI)
-      throw new IllegalArgumentException("Longitude out of range");
-    this.longitude = longitude;
-
-    final double sinLongitude = Math.sin(longitude);
-    final double cosLongitude = Math.cos(longitude);
-
-    this.plane = new Plane(cosLongitude, sinLongitude);
-    // We need a bounding plane too, which is perpendicular to the longitude plane and sided so that the point (0.0, longitude) is inside.
-    this.interiorPoint = new GeoPoint(planetModel, 0.0, sinLongitude, 1.0, cosLongitude);
-    this.boundingPlane = new SidedPlane(interiorPoint, -sinLongitude, cosLongitude);
-    this.edgePoints = new GeoPoint[]{interiorPoint};
-    this.planePoints = new GeoPoint[]{planetModel.NORTH_POLE, planetModel.SOUTH_POLE};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    // Figuring out when we escalate to a special case requires some prefiguring
-    double newLeftLon = longitude - angle;
-    double newRightLon = longitude + angle;
-    double currentLonSpan = 2.0 * angle;
-    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
-      newLeftLon = -Math.PI;
-      newRightLon = Math.PI;
-    }
-    return GeoBBoxFactory.makeGeoBBox(planetModel, Math.PI * 0.5, -Math.PI * 0.5, newLeftLon, newRightLon);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return plane.evaluateIsZero(x, y, z) &&
-        boundingPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public double getRadius() {
-    return Math.PI * 0.5;
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    return interiorPoint;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    return p.intersects(planetModel, plane, notablePoints, planePoints, bounds, boundingPlane);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds
-      .addVerticalPlane(planetModel, longitude, plane, boundingPlane)
-      .addPoint(planetModel.NORTH_POLE).addPoint(planetModel.SOUTH_POLE);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    // Look for intersections.
-    if (path.intersects(plane, planePoints, boundingPlane))
-      return OVERLAPS;
-
-    if (path.isWithin(interiorPoint))
-      return CONTAINS;
-
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    final double distance = distanceStyle.computeDistance(planetModel, plane, x,y,z, boundingPlane);
-    
-    final double northDistance = distanceStyle.computeDistance(planetModel.NORTH_POLE, x,y,z);
-    final double southDistance = distanceStyle.computeDistance(planetModel.SOUTH_POLE, x,y,z);
-    
-    return Math.min(
-      distance,
-      Math.min(northDistance, southDistance));
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoDegenerateLongitudeSlice))
-      return false;
-    GeoDegenerateLongitudeSlice other = (GeoDegenerateLongitudeSlice) o;
-    return super.equals(other) && other.longitude == longitude;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    long temp = Double.doubleToLongBits(longitude);
-    result = result * 31 + (int) (temp ^ (temp >>> 32));
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoDegenerateLongitudeSlice: {planetmodel="+planetModel+", longitude=" + longitude + "(" + longitude * 180.0 / Math.PI + ")}";
-  }
-}
-  
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegeneratePoint.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegeneratePoint.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegeneratePoint.java
deleted file mode 100644
index 63670d7..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegeneratePoint.java
+++ /dev/null
@@ -1,135 +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.geo3d;
-    
-/**
- * This class represents a degenerate point bounding box.
- * It is not a simple GeoPoint because we must have the latitude and longitude.
- *
- * @lucene.internal
- */
-public class GeoDegeneratePoint extends GeoPoint implements GeoBBox, GeoCircle {
-  /** Current planet model, since we don't extend BasePlanetObject */
-  protected final PlanetModel planetModel;
-  /** Edge point is an area containing just this */
-  protected final GeoPoint[] edgePoints;
-
-  /** Constructor.
-   *@param planetModel is the planet model to use.
-   *@param lat is the latitude.
-   *@param lon is the longitude.
-   */
-  public GeoDegeneratePoint(final PlanetModel planetModel, final double lat, final double lon) {
-    super(planetModel, lat, lon);
-    this.planetModel = planetModel;
-    this.edgePoints = new GeoPoint[]{this};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    final double newTopLat = latitude + angle;
-    final double newBottomLat = latitude - angle;
-    final double newLeftLon = longitude - angle;
-    final double newRightLon = longitude + angle;
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane plane, final GeoPoint[] notablePoints, final Membership... bounds) {
-    // If not on the plane, no intersection
-    if (!plane.evaluateIsZero(this))
-      return false;
-
-    for (Membership m : bounds) {
-      if (!m.isWithin(this))
-        return false;
-    }
-    return true;
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    bounds.addPoint(this);
-  }
-
-  @Override
-  public double computeOutsideDistance(final DistanceStyle distanceStyle, final GeoPoint point) {
-    return distanceStyle.computeDistance(this, point);
-  }
-
-  @Override
-  public double computeOutsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    return distanceStyle.computeDistance(this, x,y,z);
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoDegeneratePoint))
-      return false;
-    GeoDegeneratePoint other = (GeoDegeneratePoint) o;
-    return super.equals(other) && other.latitude == latitude && other.longitude == longitude;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoDegeneratePoint: {planetmodel="+planetModel+", lat=" + latitude + "(" + latitude * 180.0 / Math.PI + "), lon=" + longitude + "(" + longitude * 180.0 / Math.PI + ")}";
-  }
-
-  @Override
-  public boolean isWithin(final Vector point) {
-    return isWithin(point.x, point.y, point.z);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return x == this.x && y == this.y && z == this.z;
-  }
-
-  @Override
-  public double getRadius() {
-    return 0.0;
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    return this;
-  }
-
-  @Override
-  public int getRelationship(final GeoShape shape) {
-    if (shape.isWithin(this)) {
-      //System.err.println("Degenerate point "+this+" is WITHIN shape "+shape);
-      return CONTAINS;
-    }
-
-    //System.err.println("Degenerate point "+this+" is NOT within shape "+shape);
-    return DISJOINT;
-  }
-
-  @Override
-  public double computeDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    if (isWithin(x,y,z))
-      return 0.0;
-    return Double.MAX_VALUE;
-  }
-}
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateVerticalLine.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateVerticalLine.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateVerticalLine.java
deleted file mode 100644
index f21f774..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDegenerateVerticalLine.java
+++ /dev/null
@@ -1,205 +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.geo3d;
-
-/**
- * Degenerate bounding box limited on two sides (top lat, bottom lat).
- *
- * @lucene.internal
- */
-public class GeoDegenerateVerticalLine extends GeoBaseBBox {
-  /** Top latitude of the vertical line */
-  protected final double topLat;
-  /** Bottom latitude of the vertical line */
-  protected final double bottomLat;
-  /** Longitude of the vertical line */
-  protected final double longitude;
-
-  /** Point at the upper end of the vertical line */
-  protected final GeoPoint UHC;
-  /** Point at the lower end of the vertical line */
-  protected final GeoPoint LHC;
-
-  /** Top end cutoff plane */
-  protected final SidedPlane topPlane;
-  /** Bottom end cutoff plane */
-  protected final SidedPlane bottomPlane;
-  /** Back-side cutoff plane */
-  protected final SidedPlane boundingPlane;
-  /** The vertical line plane */
-  protected final Plane plane;
-  /** Notable points for the line (end points) */
-  protected final GeoPoint[] planePoints;
-  /** A computed center point for the line */
-  protected final GeoPoint centerPoint;
-  /** A point that's on the line */
-  protected final GeoPoint[] edgePoints;
-
-  /**
-   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, longitude: {@code -PI -> PI}
-   */
-  public GeoDegenerateVerticalLine(final PlanetModel planetModel, final double topLat, final double bottomLat, final double longitude) {
-    super(planetModel);
-    // Argument checking
-    if (topLat > Math.PI * 0.5 || topLat < -Math.PI * 0.5)
-      throw new IllegalArgumentException("Top latitude out of range");
-    if (bottomLat > Math.PI * 0.5 || bottomLat < -Math.PI * 0.5)
-      throw new IllegalArgumentException("Bottom latitude out of range");
-    if (topLat < bottomLat)
-      throw new IllegalArgumentException("Top latitude less than bottom latitude");
-    if (longitude < -Math.PI || longitude > Math.PI)
-      throw new IllegalArgumentException("Longitude out of range");
-
-    this.topLat = topLat;
-    this.bottomLat = bottomLat;
-    this.longitude = longitude;
-
-    final double sinTopLat = Math.sin(topLat);
-    final double cosTopLat = Math.cos(topLat);
-    final double sinBottomLat = Math.sin(bottomLat);
-    final double cosBottomLat = Math.cos(bottomLat);
-    final double sinLongitude = Math.sin(longitude);
-    final double cosLongitude = Math.cos(longitude);
-
-    // Now build the two points
-    this.UHC = new GeoPoint(planetModel, sinTopLat, sinLongitude, cosTopLat, cosLongitude, topLat, longitude);
-    this.LHC = new GeoPoint(planetModel, sinBottomLat, sinLongitude, cosBottomLat, cosLongitude, bottomLat, longitude);
-
-    this.plane = new Plane(cosLongitude, sinLongitude);
-
-    final double middleLat = (topLat + bottomLat) * 0.5;
-    final double sinMiddleLat = Math.sin(middleLat);
-    final double cosMiddleLat = Math.cos(middleLat);
-
-    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinLongitude, cosMiddleLat, cosLongitude);
-
-    this.topPlane = new SidedPlane(centerPoint, planetModel, sinTopLat);
-    this.bottomPlane = new SidedPlane(centerPoint, planetModel, sinBottomLat);
-
-    this.boundingPlane = new SidedPlane(centerPoint, -sinLongitude, cosLongitude);
-
-    this.planePoints = new GeoPoint[]{UHC, LHC};
-
-    this.edgePoints = new GeoPoint[]{centerPoint};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    final double newTopLat = topLat + angle;
-    final double newBottomLat = bottomLat - angle;
-    double newLeftLon = longitude - angle;
-    double newRightLon = longitude + angle;
-    double currentLonSpan = 2.0 * angle;
-    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
-      newLeftLon = -Math.PI;
-      newRightLon = Math.PI;
-    }
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return plane.evaluateIsZero(x, y, z) &&
-        boundingPlane.isWithin(x, y, z) &&
-        topPlane.isWithin(x, y, z) &&
-        bottomPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public double getRadius() {
-    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
-    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
-    // the distance to the right or left edge from the center.
-    final double topAngle = centerPoint.arcDistance(UHC);
-    final double bottomAngle = centerPoint.arcDistance(LHC);
-    return Math.max(topAngle, bottomAngle);
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    return centerPoint;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    return p.intersects(planetModel, plane, notablePoints, planePoints, bounds, boundingPlane, topPlane, bottomPlane);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds.addVerticalPlane(planetModel, longitude, plane, boundingPlane, topPlane, bottomPlane)
-      .addPoint(UHC).addPoint(LHC);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    //System.err.println(this+" relationship to "+path);
-    if (path.intersects(plane, planePoints, boundingPlane, topPlane, bottomPlane)) {
-      //System.err.println(" overlaps");
-      return OVERLAPS;
-    }
-
-    if (path.isWithin(centerPoint)) {
-      //System.err.println(" contains");
-      return CONTAINS;
-    }
-
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    final double distance = distanceStyle.computeDistance(planetModel, plane, x,y,z, topPlane, bottomPlane, boundingPlane);
-    
-    final double UHCDistance = distanceStyle.computeDistance(UHC, x,y,z);
-    final double LHCDistance = distanceStyle.computeDistance(LHC, x,y,z);
-    
-    return Math.min(
-      distance,
-      Math.min(UHCDistance, LHCDistance));
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoDegenerateVerticalLine))
-      return false;
-    GeoDegenerateVerticalLine other = (GeoDegenerateVerticalLine) o;
-    return super.equals(other) && other.UHC.equals(UHC) && other.LHC.equals(LHC);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + UHC.hashCode();
-    result = 31 * result + LHC.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoDegenerateVerticalLine: {longitude=" + longitude + "(" + longitude * 180.0 / Math.PI + "), toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + "), bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + ")}";
-  }
-}
-  
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDistance.java
deleted file mode 100755
index 899a687..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDistance.java
+++ /dev/null
@@ -1,59 +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.geo3d;
-
-/**
- * An implementer of this interface is capable of computing the described "distance" values,
- * which are meant to provide both actual distance values, as well as
- * distance estimates that can be computed more cheaply.
- *
- * @lucene.experimental
- */
-public interface GeoDistance extends Membership {
-  
-  // The following methods compute distances from the shape to a point
-  // expected to be INSIDE the shape.  Typically a value of Double.MAX_VALUE
-  // is returned for points that happen to be outside the shape.
-
-  /**
-   * Compute this shape's <em>internal</em> "distance" to the GeoPoint.
-   * Implementations should clarify how this is computed when it's non-obvious.
-   * A return value of Double.MAX_VALUE should be returned for
-   * points outside of the shape.
-   *
-   * @param distanceStyle is the distance style.
-   * @param point is the point to compute the distance to.
-   * @return the distance.
-   */
-  public default double computeDistance(final DistanceStyle distanceStyle, final GeoPoint point) {
-    return computeDistance(distanceStyle, point.x, point.y, point.z);
-  }
-
-  /**
-   * Compute this shape's <em>internal</em> "distance" to the GeoPoint.
-   * Implementations should clarify how this is computed when it's non-obvious.
-   * A return value of Double.MAX_VALUE should be returned for
-   * points outside of the shape.
-   *
-   * @param x is the point's unit x coordinate (using U.S. convention).
-   * @param y is the point's unit y coordinate (using U.S. convention).
-   * @param z is the point's unit z coordinate (using U.S. convention).
-   * @return the distance.
-   */
-  public double computeDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z);
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDistanceShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDistanceShape.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDistanceShape.java
deleted file mode 100755
index 1e82f48..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoDistanceShape.java
+++ /dev/null
@@ -1,27 +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.geo3d;
-
-/**
- * Distance shapes have capabilities of both geohashing and distance
- * computation (which also includes point membership determination).
- *
- * @lucene.experimental
- */
-public interface GeoDistanceShape extends GeoMembershipShape, GeoDistance {
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoLatitudeZone.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoLatitudeZone.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoLatitudeZone.java
deleted file mode 100755
index 3fc4423..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoLatitudeZone.java
+++ /dev/null
@@ -1,198 +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.geo3d;
-
-/**
- * This GeoBBox represents an area rectangle limited only in latitude.
- *
- * @lucene.internal
- */
-public class GeoLatitudeZone extends GeoBaseBBox {
-  /** The top latitude of the zone */
-  protected final double topLat;
-  /** The bottom latitude of the zone */
-  protected final double bottomLat;
-  /** Cosine of the top lat */
-  protected final double cosTopLat;
-  /** Cosine of the bottom lat */
-  protected final double cosBottomLat;
-  /** The top plane */
-  protected final SidedPlane topPlane;
-  /** The bottom plane */
-  protected final SidedPlane bottomPlane;
-  /** An interior point */
-  protected final GeoPoint interiorPoint;
-  /** Notable points (none) */
-  protected final static GeoPoint[] planePoints = new GeoPoint[0];
-
-  // We need two additional points because a latitude zone's boundaries don't intersect.  This is a very
-  // special case that most GeoBBox's do not have.
-  
-  /** Top boundary point */
-  protected final GeoPoint topBoundaryPoint;
-  /** Bottom boundary point */
-  protected final GeoPoint bottomBoundaryPoint;
-  /** A point on each distinct edge */
-  protected final GeoPoint[] edgePoints;
-
-  /** Constructor.
-   *@param planetModel is the planet model to use.
-   *@param topLat is the top latitude.
-   *@param bottomLat is the bottom latitude.
-   */
-  public GeoLatitudeZone(final PlanetModel planetModel, final double topLat, final double bottomLat) {
-    super(planetModel);
-    this.topLat = topLat;
-    this.bottomLat = bottomLat;
-
-    final double sinTopLat = Math.sin(topLat);
-    final double sinBottomLat = Math.sin(bottomLat);
-    this.cosTopLat = Math.cos(topLat);
-    this.cosBottomLat = Math.cos(bottomLat);
-
-    // Compute an interior point.  Pick one whose lat is between top and bottom.
-    final double middleLat = (topLat + bottomLat) * 0.5;
-    final double sinMiddleLat = Math.sin(middleLat);
-    this.interiorPoint = new GeoPoint(planetModel, sinMiddleLat, 0.0, Math.sqrt(1.0 - sinMiddleLat * sinMiddleLat), 1.0);
-    this.topBoundaryPoint = new GeoPoint(planetModel, sinTopLat, 0.0, Math.sqrt(1.0 - sinTopLat * sinTopLat), 1.0);
-    this.bottomBoundaryPoint = new GeoPoint(planetModel, sinBottomLat, 0.0, Math.sqrt(1.0 - sinBottomLat * sinBottomLat), 1.0);
-
-    this.topPlane = new SidedPlane(interiorPoint, planetModel, sinTopLat);
-    this.bottomPlane = new SidedPlane(interiorPoint, planetModel, sinBottomLat);
-
-    this.edgePoints = new GeoPoint[]{topBoundaryPoint, bottomBoundaryPoint};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    final double newTopLat = topLat + angle;
-    final double newBottomLat = bottomLat - angle;
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, -Math.PI, Math.PI);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return topPlane.isWithin(x, y, z) &&
-        bottomPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public double getRadius() {
-    // This is a bit tricky.  I guess we should interpret this as meaning the angle of a circle that
-    // would contain all the bounding box points, when starting in the "center".
-    if (topLat > 0.0 && bottomLat < 0.0)
-      return Math.PI;
-    double maxCosLat = cosTopLat;
-    if (maxCosLat < cosBottomLat)
-      maxCosLat = cosBottomLat;
-    return maxCosLat * Math.PI;
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    // This is totally arbitrary and only a cartesian could agree with it.
-    return interiorPoint;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    return p.intersects(planetModel, topPlane, notablePoints, planePoints, bounds, bottomPlane) ||
-        p.intersects(planetModel, bottomPlane, notablePoints, planePoints, bounds, topPlane);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds.noLongitudeBound()
-      .addHorizontalPlane(planetModel, topLat, topPlane)
-      .addHorizontalPlane(planetModel, bottomLat, bottomPlane);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    final int insideRectangle = isShapeInsideBBox(path);
-    if (insideRectangle == SOME_INSIDE)
-      return OVERLAPS;
-
-    final boolean topBoundaryInsideShape = path.isWithin(topBoundaryPoint);
-    final boolean bottomBoundaryInsideShape = path.isWithin(bottomBoundaryPoint);
-
-    if (topBoundaryInsideShape && !bottomBoundaryInsideShape ||
-        !topBoundaryInsideShape && bottomBoundaryInsideShape)
-      return OVERLAPS;
-
-    final boolean insideShape = topBoundaryInsideShape && bottomBoundaryInsideShape;
-
-    if (insideRectangle == ALL_INSIDE && insideShape)
-      return OVERLAPS;
-
-    // Second, the shortcut of seeing whether endpoints are in/out is not going to
-    // work with no area endpoints.  So we rely entirely on intersections.
-
-    if (path.intersects(topPlane, planePoints, bottomPlane) ||
-        path.intersects(bottomPlane, planePoints, topPlane))
-      return OVERLAPS;
-
-    // There is another case for latitude zones only.  This is when the boundaries of the shape all fit
-    // within the zone, but the shape includes areas outside the zone crossing a pole.
-    // In this case, the above "overlaps" check is insufficient.  We also need to check a point on either boundary
-    // whether it is within the shape.  If both such points are within, then CONTAINS is the right answer.  If
-    // one such point is within, then OVERLAPS is the right answer.
-
-    if (insideShape)
-      return CONTAINS;
-
-    if (insideRectangle == ALL_INSIDE)
-      return WITHIN;
-
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    final double topDistance = distanceStyle.computeDistance(planetModel, topPlane, x,y,z, bottomPlane);
-    final double bottomDistance = distanceStyle.computeDistance(planetModel, bottomPlane, x,y,z, topPlane);
-
-    return Math.min(topDistance, bottomDistance);
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoLatitudeZone))
-      return false;
-    GeoLatitudeZone other = (GeoLatitudeZone) o;
-    return super.equals(other) && other.topBoundaryPoint.equals(topBoundaryPoint) && other.bottomBoundaryPoint.equals(bottomBoundaryPoint);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + topBoundaryPoint.hashCode();
-    result = 31 * result + bottomBoundaryPoint.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoLatitudeZone: {planetmodel="+planetModel+", toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + "), bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + ")}";
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoLongitudeSlice.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoLongitudeSlice.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoLongitudeSlice.java
deleted file mode 100755
index f5de7e7..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoLongitudeSlice.java
+++ /dev/null
@@ -1,204 +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.geo3d;
-
-/**
- * Bounding box limited on left and right.
- * The left-right maximum extent for this shape is PI; for anything larger, use
- * {@link GeoWideLongitudeSlice}.
- *
- * @lucene.internal
- */
-public class GeoLongitudeSlice extends GeoBaseBBox {
-  /** The left longitude of the slice */
-  protected final double leftLon;
-  /** The right longitude of the slice */
-  protected final double rightLon;
-  /** The left plane of the slice */
-  protected final SidedPlane leftPlane;
-  /** The right plane of the slice */
-  protected final SidedPlane rightPlane;
-  /** The notable points for the slice (north and south poles) */
-  protected final GeoPoint[] planePoints;
-  /** The center point of the slice */
-  protected final GeoPoint centerPoint;
-  /** A point on the edge of the slice */
-  protected final GeoPoint[] edgePoints;
-
-  /**
-   * Accepts only values in the following ranges: lon: {@code -PI -> PI}
-   *@param planetModel is the planet model.
-   *@param leftLon is the left longitude of the slice.
-   *@param rightLon is the right longitude of the slice.
-   */
-  public GeoLongitudeSlice(final PlanetModel planetModel, final double leftLon, double rightLon) {
-    super(planetModel);
-    // Argument checking
-    if (leftLon < -Math.PI || leftLon > Math.PI)
-      throw new IllegalArgumentException("Left longitude out of range");
-    if (rightLon < -Math.PI || rightLon > Math.PI)
-      throw new IllegalArgumentException("Right longitude out of range");
-    double extent = rightLon - leftLon;
-    if (extent < 0.0) {
-      extent += 2.0 * Math.PI;
-    }
-    if (extent > Math.PI)
-      throw new IllegalArgumentException("Width of rectangle too great");
-
-    this.leftLon = leftLon;
-    this.rightLon = rightLon;
-
-    final double sinLeftLon = Math.sin(leftLon);
-    final double cosLeftLon = Math.cos(leftLon);
-    final double sinRightLon = Math.sin(rightLon);
-    final double cosRightLon = Math.cos(rightLon);
-
-    // Normalize
-    while (leftLon > rightLon) {
-      rightLon += Math.PI * 2.0;
-    }
-    final double middleLon = (leftLon + rightLon) * 0.5;
-    this.centerPoint = new GeoPoint(planetModel, 0.0, middleLon);
-
-    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
-    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
-
-    this.planePoints = new GeoPoint[]{planetModel.NORTH_POLE, planetModel.SOUTH_POLE};
-    this.edgePoints = new GeoPoint[]{planetModel.NORTH_POLE};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    // Figuring out when we escalate to a special case requires some prefiguring
-    double currentLonSpan = rightLon - leftLon;
-    if (currentLonSpan < 0.0)
-      currentLonSpan += Math.PI * 2.0;
-    double newLeftLon = leftLon - angle;
-    double newRightLon = rightLon + angle;
-    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
-      newLeftLon = -Math.PI;
-      newRightLon = Math.PI;
-    }
-    return GeoBBoxFactory.makeGeoBBox(planetModel, Math.PI * 0.5, -Math.PI * 0.5, newLeftLon, newRightLon);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return leftPlane.isWithin(x, y, z) &&
-        rightPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public double getRadius() {
-    // Compute the extent and divide by two
-    double extent = rightLon - leftLon;
-    if (extent < 0.0)
-      extent += Math.PI * 2.0;
-    return Math.max(Math.PI * 0.5, extent * 0.5);
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    return centerPoint;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    return p.intersects(planetModel, leftPlane, notablePoints, planePoints, bounds, rightPlane) ||
-        p.intersects(planetModel, rightPlane, notablePoints, planePoints, bounds, leftPlane);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds
-      .addVerticalPlane(planetModel, leftLon, leftPlane, rightPlane)
-      .addVerticalPlane(planetModel, rightLon, rightPlane, leftPlane)
-      .addPoint(planetModel.NORTH_POLE)
-      .addPoint(planetModel.SOUTH_POLE);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    final int insideRectangle = isShapeInsideBBox(path);
-    if (insideRectangle == SOME_INSIDE)
-      return OVERLAPS;
-
-    final boolean insideShape = path.isWithin(planetModel.NORTH_POLE);
-
-    if (insideRectangle == ALL_INSIDE && insideShape)
-      return OVERLAPS;
-
-    if (path.intersects(leftPlane, planePoints, rightPlane) ||
-        path.intersects(rightPlane, planePoints, leftPlane)) {
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      return WITHIN;
-    }
-
-    if (insideShape) {
-      return CONTAINS;
-    }
-
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, rightPlane);
-    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, leftPlane);
-    
-    final double northDistance = distanceStyle.computeDistance(planetModel.NORTH_POLE, x,y,z);
-    final double southDistance = distanceStyle.computeDistance(planetModel.SOUTH_POLE, x,y,z);
-    
-    return
-      Math.min(
-        Math.min(northDistance, southDistance),
-        Math.min(leftDistance, rightDistance));
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoLongitudeSlice))
-      return false;
-    GeoLongitudeSlice other = (GeoLongitudeSlice) o;
-    return super.equals(other) && other.leftLon == leftLon && other.rightLon == rightLon;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    long temp = Double.doubleToLongBits(leftLon);
-    result = 31 * result + (int) (temp ^ (temp >>> 32));
-    temp = Double.doubleToLongBits(rightLon);
-    result = 31 * result + (int) (temp ^ (temp >>> 32));
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoLongitudeSlice: {planetmodel="+planetModel+", leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
-  }
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoMembershipShape.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoMembershipShape.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoMembershipShape.java
deleted file mode 100755
index 54b2551..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoMembershipShape.java
+++ /dev/null
@@ -1,27 +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.geo3d;
-
-/**
- * Membership shapes have capabilities of both geohashing and membership
- * determination.
- *
- * @lucene.experimental
- */
-public interface GeoMembershipShape extends GeoShape, GeoOutsideDistance, Membership {
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoNorthLatitudeZone.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoNorthLatitudeZone.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoNorthLatitudeZone.java
deleted file mode 100644
index 43338bb..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoNorthLatitudeZone.java
+++ /dev/null
@@ -1,165 +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.geo3d;
-
-/**
- * This GeoBBox represents an area rectangle limited only in south latitude.
- *
- * @lucene.internal
- */
-public class GeoNorthLatitudeZone extends GeoBaseBBox {
-  /** The bottom latitude of the zone */
-  protected final double bottomLat;
-  /** Cosine of the bottom latitude of the zone */
-  protected final double cosBottomLat;
-  /** The bottom plane of the zone */
-  protected final SidedPlane bottomPlane;
-  /** An interior point of the zone */
-  protected final GeoPoint interiorPoint;
-  /** Notable points: none */
-  protected final static GeoPoint[] planePoints = new GeoPoint[0];
-  /** A point on the bottom boundary */
-  protected final GeoPoint bottomBoundaryPoint;
-  /** A reference to the point on the boundary */
-  protected final GeoPoint[] edgePoints;
-
-  /** Constructor.
-   *@param planetModel is the planet model.
-   *@param bottomLat is the bottom latitude.
-   */
-  public GeoNorthLatitudeZone(final PlanetModel planetModel, final double bottomLat) {
-    super(planetModel);
-    this.bottomLat = bottomLat;
-
-    final double sinBottomLat = Math.sin(bottomLat);
-    this.cosBottomLat = Math.cos(bottomLat);
-
-    // Compute an interior point.  Pick one whose lat is between top and bottom.
-    final double middleLat = (Math.PI * 0.5 + bottomLat) * 0.5;
-    final double sinMiddleLat = Math.sin(middleLat);
-    this.interiorPoint = new GeoPoint(planetModel, sinMiddleLat, 0.0, Math.sqrt(1.0 - sinMiddleLat * sinMiddleLat), 1.0);
-    this.bottomBoundaryPoint = new GeoPoint(planetModel, sinBottomLat, 0.0, Math.sqrt(1.0 - sinBottomLat * sinBottomLat), 1.0);
-
-    this.bottomPlane = new SidedPlane(interiorPoint, planetModel, sinBottomLat);
-
-    this.edgePoints = new GeoPoint[]{bottomBoundaryPoint};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    final double newTopLat = Math.PI * 0.5;
-    final double newBottomLat = bottomLat - angle;
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, -Math.PI, Math.PI);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return
-        bottomPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public double getRadius() {
-    // This is a bit tricky.  I guess we should interpret this as meaning the angle of a circle that
-    // would contain all the bounding box points, when starting in the "center".
-    if (bottomLat < 0.0)
-      return Math.PI;
-    double maxCosLat = cosBottomLat;
-    return maxCosLat * Math.PI;
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    return interiorPoint;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    return
-        p.intersects(planetModel, bottomPlane, notablePoints, planePoints, bounds);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds
-      .addHorizontalPlane(planetModel, bottomLat, bottomPlane);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    final int insideRectangle = isShapeInsideBBox(path);
-    if (insideRectangle == SOME_INSIDE)
-      return OVERLAPS;
-
-    final boolean insideShape = path.isWithin(bottomBoundaryPoint);
-
-    if (insideRectangle == ALL_INSIDE && insideShape)
-      return OVERLAPS;
-
-    // Second, the shortcut of seeing whether endpoints are in/out is not going to
-    // work with no area endpoints.  So we rely entirely on intersections.
-
-    if (path.intersects(bottomPlane, planePoints))
-      return OVERLAPS;
-
-    // There is another case for latitude zones only.  This is when the boundaries of the shape all fit
-    // within the zone, but the shape includes areas outside the zone crossing a pole.
-    // In this case, the above "overlaps" check is insufficient.  We also need to check a point on either boundary
-    // whether it is within the shape.  If both such points are within, then CONTAINS is the right answer.  If
-    // one such point is within, then OVERLAPS is the right answer.
-
-    if (insideShape)
-      return CONTAINS;
-
-    if (insideRectangle == ALL_INSIDE)
-      return WITHIN;
-
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    return distanceStyle.computeDistance(planetModel, bottomPlane, x,y,z);
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoNorthLatitudeZone))
-      return false;
-    GeoNorthLatitudeZone other = (GeoNorthLatitudeZone) o;
-    return super.equals(other) && other.bottomBoundaryPoint.equals(bottomBoundaryPoint);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + bottomBoundaryPoint.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoNorthLatitudeZone: {planetmodel="+planetModel+", bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + ")}";
-  }
-}
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoNorthRectangle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoNorthRectangle.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoNorthRectangle.java
deleted file mode 100644
index 66b9480..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoNorthRectangle.java
+++ /dev/null
@@ -1,263 +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.geo3d;
-
-/**
- * Bounding box limited on three sides (bottom lat, left lon, right lon), including
- * the north pole.
- * The left-right maximum extent for this shape is PI; for anything larger, use
- * {@link GeoWideNorthRectangle}.
- *
- * @lucene.internal
- */
-public class GeoNorthRectangle extends GeoBaseBBox {
-  /** The bottom latitude of the rectangle */
-  protected final double bottomLat;
-  /** The left longitude */
-  protected final double leftLon;
-  /** The right longitude */
-  protected final double rightLon;
-  /** Cosine of the middle latitude */
-  protected final double cosMiddleLat;
-  /** Lower right hand corner point */
-  protected final GeoPoint LRHC;
-  /** Lower left hand corner point */
-  protected final GeoPoint LLHC;
-  /** Bottom edge plane */
-  protected final SidedPlane bottomPlane;
-  /** Left-side plane */
-  protected final SidedPlane leftPlane;
-  /** Right-side plane */
-  protected final SidedPlane rightPlane;
-  /** Bottom plane notable points */
-  protected final GeoPoint[] bottomPlanePoints;
-  /** Left plane notable points */
-  protected final GeoPoint[] leftPlanePoints;
-  /** Right plane notable points */
-  protected final GeoPoint[] rightPlanePoints;
-  /** Center point */
-  protected final GeoPoint centerPoint;
-  /** A point on the edge */
-  protected final GeoPoint[] edgePoints;
-
-  /**
-   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
-   *@param planetModel is the planet model.
-   *@param bottomLat is the bottom latitude.
-   *@param leftLon is the left longitude.
-   *@param rightLon is the right longitude.
-   */
-  public GeoNorthRectangle(final PlanetModel planetModel, final double bottomLat, final double leftLon, double rightLon) {
-    super(planetModel);
-    // Argument checking
-    if (bottomLat > Math.PI * 0.5 || bottomLat < -Math.PI * 0.5)
-      throw new IllegalArgumentException("Bottom latitude out of range");
-    if (leftLon < -Math.PI || leftLon > Math.PI)
-      throw new IllegalArgumentException("Left longitude out of range");
-    if (rightLon < -Math.PI || rightLon > Math.PI)
-      throw new IllegalArgumentException("Right longitude out of range");
-    double extent = rightLon - leftLon;
-    if (extent < 0.0) {
-      extent += 2.0 * Math.PI;
-    }
-    if (extent > Math.PI)
-      throw new IllegalArgumentException("Width of rectangle too great");
-
-    this.bottomLat = bottomLat;
-    this.leftLon = leftLon;
-    this.rightLon = rightLon;
-
-    final double sinBottomLat = Math.sin(bottomLat);
-    final double cosBottomLat = Math.cos(bottomLat);
-    final double sinLeftLon = Math.sin(leftLon);
-    final double cosLeftLon = Math.cos(leftLon);
-    final double sinRightLon = Math.sin(rightLon);
-    final double cosRightLon = Math.cos(rightLon);
-
-    // Now build the points
-    this.LRHC = new GeoPoint(planetModel, sinBottomLat, sinRightLon, cosBottomLat, cosRightLon, bottomLat, rightLon);
-    this.LLHC = new GeoPoint(planetModel, sinBottomLat, sinLeftLon, cosBottomLat, cosLeftLon, bottomLat, leftLon);
-
-    final double middleLat = (Math.PI * 0.5 + bottomLat) * 0.5;
-    final double sinMiddleLat = Math.sin(middleLat);
-    this.cosMiddleLat = Math.cos(middleLat);
-    // Normalize
-    while (leftLon > rightLon) {
-      rightLon += Math.PI * 2.0;
-    }
-    final double middleLon = (leftLon + rightLon) * 0.5;
-    final double sinMiddleLon = Math.sin(middleLon);
-    final double cosMiddleLon = Math.cos(middleLon);
-
-    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinMiddleLon, cosMiddleLat, cosMiddleLon);
-
-    this.bottomPlane = new SidedPlane(centerPoint, planetModel, sinBottomLat);
-    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
-    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
-
-    this.bottomPlanePoints = new GeoPoint[]{LLHC, LRHC};
-    this.leftPlanePoints = new GeoPoint[]{planetModel.NORTH_POLE, LLHC};
-    this.rightPlanePoints = new GeoPoint[]{planetModel.NORTH_POLE, LRHC};
-
-    this.edgePoints = new GeoPoint[]{planetModel.NORTH_POLE};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    final double newTopLat = Math.PI * 0.5;
-    final double newBottomLat = bottomLat - angle;
-    // Figuring out when we escalate to a special case requires some prefiguring
-    double currentLonSpan = rightLon - leftLon;
-    if (currentLonSpan < 0.0)
-      currentLonSpan += Math.PI * 2.0;
-    double newLeftLon = leftLon - angle;
-    double newRightLon = rightLon + angle;
-    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
-      newLeftLon = -Math.PI;
-      newRightLon = Math.PI;
-    }
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return
-        bottomPlane.isWithin(x, y, z) &&
-            leftPlane.isWithin(x, y, z) &&
-            rightPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public double getRadius() {
-    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
-    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
-    // the distance to the right or left edge from the center.
-    final double centerAngle = (rightLon - (rightLon + leftLon) * 0.5) * cosMiddleLat;
-    final double bottomAngle = centerPoint.arcDistance(LLHC);
-    return Math.max(centerAngle, bottomAngle);
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  /**
-   * Returns the center of a circle into which the area will be inscribed.
-   *
-   * @return the center.
-   */
-  @Override
-  public GeoPoint getCenter() {
-    return centerPoint;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    return
-        p.intersects(planetModel, bottomPlane, notablePoints, bottomPlanePoints, bounds, leftPlane, rightPlane) ||
-            p.intersects(planetModel, leftPlane, notablePoints, leftPlanePoints, bounds, rightPlane, bottomPlane) ||
-            p.intersects(planetModel, rightPlane, notablePoints, rightPlanePoints, bounds, leftPlane, bottomPlane);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds
-      .addHorizontalPlane(planetModel, bottomLat, bottomPlane, leftPlane, rightPlane)
-      .addVerticalPlane(planetModel, leftLon, leftPlane, bottomPlane, rightPlane)
-      .addVerticalPlane(planetModel, rightLon, rightPlane, bottomPlane, leftPlane)
-      .addPoint(LLHC).addPoint(LRHC).addPoint(planetModel.NORTH_POLE);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    //System.err.println(this+" getrelationship with "+path);
-    final int insideRectangle = isShapeInsideBBox(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some inside");
-      return OVERLAPS;
-    }
-
-    final boolean insideShape = path.isWithin(planetModel.NORTH_POLE);
-
-    if (insideRectangle == ALL_INSIDE && insideShape) {
-      //System.err.println(" inside of each other");
-      return OVERLAPS;
-    }
-
-    if (
-        path.intersects(bottomPlane, bottomPlanePoints, leftPlane, rightPlane) ||
-            path.intersects(leftPlane, leftPlanePoints, bottomPlane, rightPlane) ||
-            path.intersects(rightPlane, rightPlanePoints, leftPlane, bottomPlane)) {
-      //System.err.println(" edges intersect");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      //System.err.println(" shape inside rectangle");
-      return WITHIN;
-    }
-
-    if (insideShape) {
-      //System.err.println(" shape contains rectangle");
-      return CONTAINS;
-    }
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    final double bottomDistance = distanceStyle.computeDistance(planetModel, bottomPlane, x,y,z, leftPlane, rightPlane);
-    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, rightPlane, bottomPlane);
-    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, leftPlane, bottomPlane);
-    
-    final double LRHCDistance = distanceStyle.computeDistance(LRHC, x,y,z);
-    final double LLHCDistance = distanceStyle.computeDistance(LLHC, x,y,z);
-    
-    return
-      Math.min(
-        bottomDistance,
-        Math.min(
-          Math.min(leftDistance, rightDistance),
-          Math.min(LRHCDistance, LLHCDistance)));
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoNorthRectangle))
-      return false;
-    GeoNorthRectangle other = (GeoNorthRectangle) o;
-    return super.equals(other) && other.LLHC.equals(LLHC) && other.LRHC.equals(LRHC);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + LLHC.hashCode();
-    result = 31 * result + LRHC.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoNorthRectangle: {planetmodel="+planetModel+", bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
-  }
-}
-  
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoOutsideDistance.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoOutsideDistance.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoOutsideDistance.java
deleted file mode 100644
index c1d784d..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoOutsideDistance.java
+++ /dev/null
@@ -1,55 +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.geo3d;
-
-/**
- * Implemented by Geo3D shapes that can compute the distance from a point to the closest outside edge.
- *
- * @lucene.experimental
- */
-public interface GeoOutsideDistance extends Membership {
-  
-  // The following methods compute distances from the shape to a point
-  // expected to be OUTSIDE the shape.  Typically a value of 0.0
-  // is returned for points that happen to be within the shape.
-  
-  /**
-   * Compute this shape's distance to the GeoPoint.
-   * A return value of 0.0 should be returned for
-   * points inside of the shape.
-   * @param distanceStyle is the distance style.
-   * @param point is the point to compute the distance to.
-   * @return the distance.
-   */
-  public default double computeOutsideDistance(final DistanceStyle distanceStyle, final GeoPoint point) {
-    return computeOutsideDistance(distanceStyle, point.x, point.y, point.z);
-  }
-
-  /**
-   * Compute this shape's distance to the GeoPoint.
-   * A return value of 0.0 should be returned for
-   * points inside of the shape.
-   * @param distanceStyle is the distance style.
-   * @param x is the point's unit x coordinate (using U.S. convention).
-   * @param y is the point's unit y coordinate (using U.S. convention).
-   * @param z is the point's unit z coordinate (using U.S. convention).
-   * @return the distance.
-   */
-  public double computeOutsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z);
-
-}
-


[13/32] lucene-solr git commit: LUCENE-7056: Geo3D package re-org (cherry picked from commit 0093e26)

Posted by ds...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoSouthRectangle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoSouthRectangle.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoSouthRectangle.java
deleted file mode 100644
index eb6526b..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoSouthRectangle.java
+++ /dev/null
@@ -1,259 +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.geo3d;
-
-/**
- * Bounding box limited on three sides (top lat, left lon, right lon).  The
- * other corner is the south pole.
- * The left-right maximum extent for this shape is PI; for anything larger, use
- * {@link GeoWideSouthRectangle}.
- *
- * @lucene.internal
- */
-public class GeoSouthRectangle extends GeoBaseBBox {
-  /** The top latitude of the rect */
-  protected final double topLat;
-  /** The left longitude of the rect */
-  protected final double leftLon;
-  /** The right longitude of the rect */
-  protected final double rightLon;
-  /** The cosine of a middle latitude */
-  protected final double cosMiddleLat;
-  /** The upper left hand corner of the rectangle */
-  protected final GeoPoint ULHC;
-  /** The upper right hand corner of the rectangle */
-  protected final GeoPoint URHC;
-
-  /** The top plane */
-  protected final SidedPlane topPlane;
-  /** The left plane */
-  protected final SidedPlane leftPlane;
-  /** The right plane */
-  protected final SidedPlane rightPlane;
-
-  /** Notable points for the top plane */
-  protected final GeoPoint[] topPlanePoints;
-  /** Notable points for the left plane */
-  protected final GeoPoint[] leftPlanePoints;
-  /** Notable points for the right plane */
-  protected final GeoPoint[] rightPlanePoints;
-
-  /** The center point */
-  protected final GeoPoint centerPoint;
-
-  /** A point on the edge */
-  protected final GeoPoint[] edgePoints;
-
-  /**
-   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
-   *@param planetModel is the planet model.
-   *@param topLat is the top latitude.
-   *@param leftLon is the left longitude.
-   *@param rightLon is the right longitude.
-   */
-  public GeoSouthRectangle(final PlanetModel planetModel, final double topLat, final double leftLon, double rightLon) {
-    super(planetModel);
-    // Argument checking
-    if (topLat > Math.PI * 0.5 || topLat < -Math.PI * 0.5)
-      throw new IllegalArgumentException("Top latitude out of range");
-    if (leftLon < -Math.PI || leftLon > Math.PI)
-      throw new IllegalArgumentException("Left longitude out of range");
-    if (rightLon < -Math.PI || rightLon > Math.PI)
-      throw new IllegalArgumentException("Right longitude out of range");
-    double extent = rightLon - leftLon;
-    if (extent < 0.0) {
-      extent += 2.0 * Math.PI;
-    }
-    if (extent > Math.PI)
-      throw new IllegalArgumentException("Width of rectangle too great");
-
-    this.topLat = topLat;
-    this.leftLon = leftLon;
-    this.rightLon = rightLon;
-
-    final double sinTopLat = Math.sin(topLat);
-    final double cosTopLat = Math.cos(topLat);
-    final double sinLeftLon = Math.sin(leftLon);
-    final double cosLeftLon = Math.cos(leftLon);
-    final double sinRightLon = Math.sin(rightLon);
-    final double cosRightLon = Math.cos(rightLon);
-
-    // Now build the four points
-    this.ULHC = new GeoPoint(planetModel, sinTopLat, sinLeftLon, cosTopLat, cosLeftLon, topLat, leftLon);
-    this.URHC = new GeoPoint(planetModel, sinTopLat, sinRightLon, cosTopLat, cosRightLon, topLat, rightLon);
-
-    final double middleLat = (topLat - Math.PI * 0.5) * 0.5;
-    final double sinMiddleLat = Math.sin(middleLat);
-    this.cosMiddleLat = Math.cos(middleLat);
-    // Normalize
-    while (leftLon > rightLon) {
-      rightLon += Math.PI * 2.0;
-    }
-    final double middleLon = (leftLon + rightLon) * 0.5;
-    final double sinMiddleLon = Math.sin(middleLon);
-    final double cosMiddleLon = Math.cos(middleLon);
-
-    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinMiddleLon, cosMiddleLat, cosMiddleLon);
-
-    this.topPlane = new SidedPlane(centerPoint, planetModel, sinTopLat);
-    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
-    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
-
-    this.topPlanePoints = new GeoPoint[]{ULHC, URHC};
-    this.leftPlanePoints = new GeoPoint[]{ULHC, planetModel.SOUTH_POLE};
-    this.rightPlanePoints = new GeoPoint[]{URHC, planetModel.SOUTH_POLE};
-    
-    this.edgePoints = new GeoPoint[]{planetModel.SOUTH_POLE};
-
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    final double newTopLat = topLat + angle;
-    final double newBottomLat = -Math.PI * 0.5;
-    // Figuring out when we escalate to a special case requires some prefiguring
-    double currentLonSpan = rightLon - leftLon;
-    if (currentLonSpan < 0.0)
-      currentLonSpan += Math.PI * 2.0;
-    double newLeftLon = leftLon - angle;
-    double newRightLon = rightLon + angle;
-    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
-      newLeftLon = -Math.PI;
-      newRightLon = Math.PI;
-    }
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return topPlane.isWithin(x, y, z) &&
-        leftPlane.isWithin(x, y, z) &&
-        rightPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public double getRadius() {
-    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
-    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
-    // the distance to the right or left edge from the center.
-    final double centerAngle = (rightLon - (rightLon + leftLon) * 0.5) * cosMiddleLat;
-    final double topAngle = centerPoint.arcDistance(URHC);
-    return Math.max(centerAngle, topAngle);
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    return centerPoint;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    return p.intersects(planetModel, topPlane, notablePoints, topPlanePoints, bounds, leftPlane, rightPlane) ||
-        p.intersects(planetModel, leftPlane, notablePoints, leftPlanePoints, bounds, rightPlane, topPlane) ||
-        p.intersects(planetModel, rightPlane, notablePoints, rightPlanePoints, bounds, leftPlane, topPlane);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds
-      .addHorizontalPlane(planetModel, topLat, topPlane, leftPlane, rightPlane)
-      .addVerticalPlane(planetModel, leftLon, leftPlane, topPlane, rightPlane)
-      .addVerticalPlane(planetModel, rightLon, rightPlane, topPlane, leftPlane)
-      .addPoint(URHC).addPoint(ULHC).addPoint(planetModel.SOUTH_POLE);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    //System.err.println(this+" getrelationship with "+path);
-    final int insideRectangle = isShapeInsideBBox(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some inside");
-      return OVERLAPS;
-    }
-
-    final boolean insideShape = path.isWithin(planetModel.SOUTH_POLE);
-
-    if (insideRectangle == ALL_INSIDE && insideShape) {
-      //System.err.println(" inside of each other");
-      return OVERLAPS;
-    }
-
-    if (path.intersects(topPlane, topPlanePoints, leftPlane, rightPlane) ||
-        path.intersects(leftPlane, leftPlanePoints, topPlane, rightPlane) ||
-        path.intersects(rightPlane, rightPlanePoints, leftPlane, topPlane)) {
-      //System.err.println(" edges intersect");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      //System.err.println(" shape inside rectangle");
-      return WITHIN;
-    }
-
-    if (insideShape) {
-      //System.err.println(" shape contains rectangle");
-      return CONTAINS;
-    }
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    final double topDistance = distanceStyle.computeDistance(planetModel, topPlane, x,y,z, leftPlane, rightPlane);
-    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, rightPlane, topPlane);
-    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, leftPlane, topPlane);
-    
-    final double ULHCDistance = distanceStyle.computeDistance(ULHC, x,y,z);
-    final double URHCDistance = distanceStyle.computeDistance(URHC, x,y,z);
-    
-    return Math.min(
-      Math.min(
-        topDistance,
-        Math.min(leftDistance, rightDistance)),
-      Math.min(ULHCDistance, URHCDistance));
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoSouthRectangle))
-      return false;
-    GeoSouthRectangle other = (GeoSouthRectangle) o;
-    return super.equals(other) && other.ULHC.equals(ULHC) && other.URHC.equals(URHC);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + ULHC.hashCode();
-    result = 31 * result + URHC.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoSouthRectangle: {planetmodel="+planetModel+", toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
-  }
-}
-  
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoStandardCircle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoStandardCircle.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoStandardCircle.java
deleted file mode 100755
index 0304d53..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoStandardCircle.java
+++ /dev/null
@@ -1,168 +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.geo3d;
-
-/**
- * Circular area with a center and radius.
- *
- * @lucene.experimental
- */
-public class GeoStandardCircle extends GeoBaseCircle {
-  /** Center of circle */
-  protected final GeoPoint center;
-  /** Cutoff angle of circle (not quite the same thing as radius) */
-  protected final double cutoffAngle;
-  /** The plane describing the circle (really an ellipse on a non-spherical world) */
-  protected final SidedPlane circlePlane;
-  /** A point that is on the world and on the circle plane */
-  protected final GeoPoint[] edgePoints;
-  /** Notable points for a circle -- there aren't any */
-  protected static final GeoPoint[] circlePoints = new GeoPoint[0];
-
-  /** Constructor.
-   *@param planetModel is the planet model.
-   *@param lat is the center latitude.
-   *@param lon is the center longitude.
-   *@param cutoffAngle is the cutoff angle for the circle.
-   */
-  public GeoStandardCircle(final PlanetModel planetModel, final double lat, final double lon, final double cutoffAngle) {
-    super(planetModel);
-    if (lat < -Math.PI * 0.5 || lat > Math.PI * 0.5)
-      throw new IllegalArgumentException("Latitude out of bounds");
-    if (lon < -Math.PI || lon > Math.PI)
-      throw new IllegalArgumentException("Longitude out of bounds");
-    if (cutoffAngle < 0.0 || cutoffAngle > Math.PI)
-      throw new IllegalArgumentException("Cutoff angle out of bounds");
-    if (cutoffAngle < Vector.MINIMUM_RESOLUTION)
-      throw new IllegalArgumentException("Cutoff angle cannot be effectively zero");
-    this.center = new GeoPoint(planetModel, lat, lon);
-    // In an ellipsoidal world, cutoff distances make no sense, unfortunately.  Only membership
-    // can be used to make in/out determination.
-    this.cutoffAngle = cutoffAngle;
-    // Compute two points on the circle, with the right angle from the center.  We'll use these
-    // to obtain the perpendicular plane to the circle.
-    double upperLat = lat + cutoffAngle;
-    double upperLon = lon;
-    if (upperLat > Math.PI * 0.5) {
-      upperLon += Math.PI;
-      if (upperLon > Math.PI)
-        upperLon -= 2.0 * Math.PI;
-      upperLat = Math.PI - upperLat;
-    }
-    double lowerLat = lat - cutoffAngle;
-    double lowerLon = lon;
-    if (lowerLat < -Math.PI * 0.5) {
-      lowerLon += Math.PI;
-      if (lowerLon > Math.PI)
-        lowerLon -= 2.0 * Math.PI;
-      lowerLat = -Math.PI - lowerLat;
-    }
-    final GeoPoint upperPoint = new GeoPoint(planetModel, upperLat, upperLon);
-    final GeoPoint lowerPoint = new GeoPoint(planetModel, lowerLat, lowerLon);
-    if (Math.abs(cutoffAngle - Math.PI) < Vector.MINIMUM_RESOLUTION) {
-      // Circle is the whole world
-      this.circlePlane = null;
-      this.edgePoints = new GeoPoint[0];
-    } else {
-      // Construct normal plane
-      final Plane normalPlane = Plane.constructNormalizedZPlane(upperPoint, lowerPoint, center);
-      // Construct a sided plane that goes through the two points and whose normal is in the normalPlane.
-      this.circlePlane = SidedPlane.constructNormalizedPerpendicularSidedPlane(center, normalPlane, upperPoint, lowerPoint);
-      if (circlePlane == null)
-        throw new IllegalArgumentException("Couldn't construct circle plane, probably too small?  Cutoff angle = "+cutoffAngle+"; upperPoint = "+upperPoint+"; lowerPoint = "+lowerPoint);
-      final GeoPoint recomputedIntersectionPoint = circlePlane.getSampleIntersectionPoint(planetModel, normalPlane);
-      if (recomputedIntersectionPoint == null)
-        throw new IllegalArgumentException("Couldn't construct intersection point, probably circle too small?  Plane = "+circlePlane);
-      this.edgePoints = new GeoPoint[]{recomputedIntersectionPoint};
-    }
-  }
-
-  @Override
-  public double getRadius() {
-    return cutoffAngle;
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    return center;
-  }
-
-  @Override
-  protected double distance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    return distanceStyle.computeDistance(this.center, x, y, z);
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    return distanceStyle.computeDistance(planetModel, circlePlane, x, y, z);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    if (circlePlane == null) {
-      return true;
-    }
-    // Fastest way of determining membership
-    return circlePlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    if (circlePlane == null) {
-      return false;
-    }
-    return circlePlane.intersects(planetModel, p, notablePoints, circlePoints, bounds);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    if (circlePlane == null) {
-      // Entire world; should already be covered
-      return;
-    }
-    bounds.addPoint(center);
-    bounds.addPlane(planetModel, circlePlane);
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoStandardCircle))
-      return false;
-    GeoStandardCircle other = (GeoStandardCircle) o;
-    return super.equals(other) && other.center.equals(center) && other.cutoffAngle == cutoffAngle;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + center.hashCode();
-    long temp = Double.doubleToLongBits(cutoffAngle);
-    result = 31 * result + (int) (temp ^ (temp >>> 32));
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoStandardCircle: {planetmodel=" + planetModel+", center=" + center + ", radius=" + cutoffAngle + "(" + cutoffAngle * 180.0 / Math.PI + ")}";
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideDegenerateHorizontalLine.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideDegenerateHorizontalLine.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideDegenerateHorizontalLine.java
deleted file mode 100644
index a9af5b2..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideDegenerateHorizontalLine.java
+++ /dev/null
@@ -1,238 +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.geo3d;
-
-/**
- * Degenerate bounding box wider than PI and limited on two sides (left lon, right lon).
- *
- * @lucene.internal
- */
-public class GeoWideDegenerateHorizontalLine extends GeoBaseBBox {
-  /** The latitude of the line */
-  protected final double latitude;
-  /** The left longitude cutoff of the line */
-  protected final double leftLon;
-  /** The right longitude cutoff of the line */
-  protected final double rightLon;
-
-  /** The left end of the line */
-  protected final GeoPoint LHC;
-  /** The right end of the line */
-  protected final GeoPoint RHC;
-
-  /** The plane the line is in */
-  protected final Plane plane;
-  /** The left cutoff plane */
-  protected final SidedPlane leftPlane;
-  /** The right cutoff plane */
-  protected final SidedPlane rightPlane;
-
-  /** Notable points for the line */
-  protected final GeoPoint[] planePoints;
-
-  /** Center point for the line */
-  protected final GeoPoint centerPoint;
-
-  /** Left/right combination bound */
-  protected final EitherBound eitherBound;
-
-  /** A point on the line */
-  protected final GeoPoint[] edgePoints;
-
-  /**
-   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}.
-   * Horizontal angle must be greater than or equal to PI.
-   *@param planetModel is the planet model.
-   *@param latitude is the line latitude.
-   *@param leftLon is the left cutoff longitude.
-   *@param rightLon is the right cutoff longitude.
-   */
-  public GeoWideDegenerateHorizontalLine(final PlanetModel planetModel, final double latitude, final double leftLon, double rightLon) {
-    super(planetModel);
-    // Argument checking
-    if (latitude > Math.PI * 0.5 || latitude < -Math.PI * 0.5)
-      throw new IllegalArgumentException("Latitude out of range");
-    if (leftLon < -Math.PI || leftLon > Math.PI)
-      throw new IllegalArgumentException("Left longitude out of range");
-    if (rightLon < -Math.PI || rightLon > Math.PI)
-      throw new IllegalArgumentException("Right longitude out of range");
-    double extent = rightLon - leftLon;
-    if (extent < 0.0) {
-      extent += 2.0 * Math.PI;
-    }
-    if (extent < Math.PI)
-      throw new IllegalArgumentException("Width of rectangle too small");
-
-    this.latitude = latitude;
-    this.leftLon = leftLon;
-    this.rightLon = rightLon;
-
-    final double sinLatitude = Math.sin(latitude);
-    final double cosLatitude = Math.cos(latitude);
-    final double sinLeftLon = Math.sin(leftLon);
-    final double cosLeftLon = Math.cos(leftLon);
-    final double sinRightLon = Math.sin(rightLon);
-    final double cosRightLon = Math.cos(rightLon);
-
-    // Now build the two points
-    this.LHC = new GeoPoint(planetModel, sinLatitude, sinLeftLon, cosLatitude, cosLeftLon, latitude, leftLon);
-    this.RHC = new GeoPoint(planetModel, sinLatitude, sinRightLon, cosLatitude, cosRightLon, latitude, rightLon);
-
-    this.plane = new Plane(planetModel, sinLatitude);
-
-    // Normalize
-    while (leftLon > rightLon) {
-      rightLon += Math.PI * 2.0;
-    }
-    double middleLon = (leftLon + rightLon) * 0.5;
-    double sinMiddleLon = Math.sin(middleLon);
-    double cosMiddleLon = Math.cos(middleLon);
-
-    this.centerPoint = new GeoPoint(planetModel, sinLatitude, sinMiddleLon, cosLatitude, cosMiddleLon);
-
-    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
-    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
-
-    this.planePoints = new GeoPoint[]{LHC, RHC};
-
-    this.eitherBound = new EitherBound();
-
-    this.edgePoints = new GeoPoint[]{centerPoint};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    final double newTopLat = latitude + angle;
-    final double newBottomLat = latitude - angle;
-    // Figuring out when we escalate to a special case requires some prefiguring
-    double currentLonSpan = rightLon - leftLon;
-    if (currentLonSpan < 0.0)
-      currentLonSpan += Math.PI * 2.0;
-    double newLeftLon = leftLon - angle;
-    double newRightLon = rightLon + angle;
-    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
-      newLeftLon = -Math.PI;
-      newRightLon = Math.PI;
-    }
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return plane.evaluateIsZero(x, y, z) &&
-        (leftPlane.isWithin(x, y, z) ||
-            rightPlane.isWithin(x, y, z));
-  }
-
-  @Override
-  public double getRadius() {
-    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
-    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
-    // the distance to the right or left edge from the center.
-    final double topAngle = centerPoint.arcDistance(RHC);
-    final double bottomAngle = centerPoint.arcDistance(LHC);
-    return Math.max(topAngle, bottomAngle);
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    return centerPoint;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    // Right and left bounds are essentially independent hemispheres; crossing into the wrong part of one
-    // requires crossing into the right part of the other.  So intersection can ignore the left/right bounds.
-    return p.intersects(planetModel, plane, notablePoints, planePoints, bounds, eitherBound);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds.isWide()
-      .addHorizontalPlane(planetModel, latitude, plane, eitherBound)
-      .addPoint(LHC)
-      .addPoint(RHC);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    if (path.intersects(plane, planePoints, eitherBound)) {
-      return OVERLAPS;
-    }
-
-    if (path.isWithin(centerPoint)) {
-      return CONTAINS;
-    }
-
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    final double distance = distanceStyle.computeDistance(planetModel, plane, x,y,z, eitherBound);
-    
-    final double LHCDistance = distanceStyle.computeDistance(LHC, x,y,z);
-    final double RHCDistance = distanceStyle.computeDistance(RHC, x,y,z);
-    
-    return Math.min(
-      distance,
-      Math.min(LHCDistance, RHCDistance));
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoWideDegenerateHorizontalLine))
-      return false;
-    GeoWideDegenerateHorizontalLine other = (GeoWideDegenerateHorizontalLine) o;
-    return super.equals(other) && other.LHC.equals(LHC) && other.RHC.equals(RHC);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + LHC.hashCode();
-    result = 31 * result + RHC.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoWideDegenerateHorizontalLine: {planetmodel="+planetModel+", latitude=" + latitude + "(" + latitude * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightLon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
-  }
-
-  /** Membership implementation representing a wide cutoff (more than 180 degrees).
-   */
-  protected class EitherBound implements Membership {
-    /** Constructor.
-     */
-    public EitherBound() {
-    }
-
-    @Override
-    public boolean isWithin(final double x, final double y, final double z) {
-      return leftPlane.isWithin(x, y, z) || rightPlane.isWithin(x, y, z);
-    }
-  }
-}
-  
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideLongitudeSlice.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideLongitudeSlice.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideLongitudeSlice.java
deleted file mode 100755
index 64e4fa8..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideLongitudeSlice.java
+++ /dev/null
@@ -1,208 +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.geo3d;
-
-/**
- * Bounding box wider than PI but limited on left and right sides (
- * left lon, right lon).
- *
- * @lucene.internal
- */
-public class GeoWideLongitudeSlice extends GeoBaseBBox {
-  /** The left longitude */
-  protected final double leftLon;
-  /** The right longitude */
-  protected final double rightLon;
-
-  /** The left plane */
-  protected final SidedPlane leftPlane;
-  /** The right plane */
-  protected final SidedPlane rightPlane;
-
-  /** Notable points for the shape */
-  protected final GeoPoint[] planePoints;
-
-  /** Center point for the shape */
-  protected final GeoPoint centerPoint;
-
-  /** A point on the edge of the shape */
-  protected final GeoPoint[] edgePoints; 
-
-  /**
-   * Accepts only values in the following ranges: lon: {@code -PI -> PI}.
-   * Horizantal angle must be greater than or equal to PI.
-   *@param planetModel is the planet model.
-   *@param leftLon is the left longitude.
-   *@param rightLon is the right longitude.
-   */
-  public GeoWideLongitudeSlice(final PlanetModel planetModel, final double leftLon, double rightLon) {
-    super(planetModel);
-    // Argument checking
-    if (leftLon < -Math.PI || leftLon > Math.PI)
-      throw new IllegalArgumentException("Left longitude out of range");
-    if (rightLon < -Math.PI || rightLon > Math.PI)
-      throw new IllegalArgumentException("Right longitude out of range");
-    double extent = rightLon - leftLon;
-    if (extent < 0.0) {
-      extent += 2.0 * Math.PI;
-    }
-    if (extent < Math.PI)
-      throw new IllegalArgumentException("Width of rectangle too small");
-
-    this.leftLon = leftLon;
-    this.rightLon = rightLon;
-
-    final double sinLeftLon = Math.sin(leftLon);
-    final double cosLeftLon = Math.cos(leftLon);
-    final double sinRightLon = Math.sin(rightLon);
-    final double cosRightLon = Math.cos(rightLon);
-
-    // Normalize
-    while (leftLon > rightLon) {
-      rightLon += Math.PI * 2.0;
-    }
-    final double middleLon = (leftLon + rightLon) * 0.5;
-    this.centerPoint = new GeoPoint(planetModel, 0.0, middleLon);
-
-    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
-    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
-    
-    this.planePoints = new GeoPoint[]{planetModel.NORTH_POLE, planetModel.SOUTH_POLE};
-    this.edgePoints = new GeoPoint[]{planetModel.NORTH_POLE};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    // Figuring out when we escalate to a special case requires some prefiguring
-    double currentLonSpan = rightLon - leftLon;
-    if (currentLonSpan < 0.0)
-      currentLonSpan += Math.PI * 2.0;
-    double newLeftLon = leftLon - angle;
-    double newRightLon = rightLon + angle;
-    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
-      newLeftLon = -Math.PI;
-      newRightLon = Math.PI;
-    }
-    return GeoBBoxFactory.makeGeoBBox(planetModel, Math.PI * 0.5, -Math.PI * 0.5, newLeftLon, newRightLon);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return leftPlane.isWithin(x, y, z) ||
-        rightPlane.isWithin(x, y, z);
-  }
-
-  @Override
-  public double getRadius() {
-    // Compute the extent and divide by two
-    double extent = rightLon - leftLon;
-    if (extent < 0.0)
-      extent += Math.PI * 2.0;
-    return Math.max(Math.PI * 0.5, extent * 0.5);
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    return centerPoint;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    // Right and left bounds are essentially independent hemispheres; crossing into the wrong part of one
-    // requires crossing into the right part of the other.  So intersection can ignore the left/right bounds.
-    return p.intersects(planetModel, leftPlane, notablePoints, planePoints, bounds) ||
-        p.intersects(planetModel, rightPlane, notablePoints, planePoints, bounds);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds.isWide()
-      .addVerticalPlane(planetModel, leftLon, leftPlane)
-      .addVerticalPlane(planetModel, rightLon, rightPlane)
-      .addPoint(planetModel.NORTH_POLE)
-      .addPoint(planetModel.SOUTH_POLE);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    final int insideRectangle = isShapeInsideBBox(path);
-    if (insideRectangle == SOME_INSIDE)
-      return OVERLAPS;
-
-    final boolean insideShape = path.isWithin(planetModel.NORTH_POLE);
-
-    if (insideRectangle == ALL_INSIDE && insideShape)
-      return OVERLAPS;
-
-    if (path.intersects(leftPlane, planePoints) ||
-        path.intersects(rightPlane, planePoints))
-      return OVERLAPS;
-
-    if (insideRectangle == ALL_INSIDE)
-      return WITHIN;
-
-    if (insideShape)
-      return CONTAINS;
-
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    // Because the rectangle exceeds 180 degrees, it is safe to compute the horizontally 
-    // unbounded distance to both the left and the right and only take the minimum of the two.
-    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z);
-    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z);
-    
-    final double northDistance = distanceStyle.computeDistance(planetModel.NORTH_POLE, x,y,z);
-    final double southDistance = distanceStyle.computeDistance(planetModel.SOUTH_POLE, x,y,z);
-    
-    return Math.min(
-      Math.min(leftDistance, rightDistance),
-      Math.min(northDistance, southDistance));
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoWideLongitudeSlice))
-      return false;
-    GeoWideLongitudeSlice other = (GeoWideLongitudeSlice) o;
-    return super.equals(other) && other.leftLon == leftLon && other.rightLon == rightLon;
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    long temp = Double.doubleToLongBits(leftLon);
-    result = 31 * result + (int) (temp ^ (temp >>> 32));
-    temp = Double.doubleToLongBits(rightLon);
-    result = 31 * result + (int) (temp ^ (temp >>> 32));
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoWideLongitudeSlice: {planetmodel="+planetModel+", leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
-  }
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideNorthRectangle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideNorthRectangle.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideNorthRectangle.java
deleted file mode 100644
index 86de584..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideNorthRectangle.java
+++ /dev/null
@@ -1,286 +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.geo3d;
-
-/**
- * Bounding box wider than PI but limited on three sides (
- * bottom lat, left lon, right lon).
- *
- * @lucene.internal
- */
-public class GeoWideNorthRectangle extends GeoBaseBBox {
-  /** Bottom latitude */
-  protected final double bottomLat;
-  /** Left longitude */
-  protected final double leftLon;
-  /** Right longitude */
-  protected final double rightLon;
-
-  /** The cosine of the middle latitude */
-  protected final double cosMiddleLat;
-
-  /** The lower right hand corner point */
-  protected final GeoPoint LRHC;
-  /** The lower left hand corner point */
-  protected final GeoPoint LLHC;
-
-  /** The bottom plane */
-  protected final SidedPlane bottomPlane;
-  /** The left plane */
-  protected final SidedPlane leftPlane;
-  /** The right plane */
-  protected final SidedPlane rightPlane;
-
-  /** Notable points for the bottom plane */
-  protected final GeoPoint[] bottomPlanePoints;
-  /** Notable points for the left plane */
-  protected final GeoPoint[] leftPlanePoints;
-  /** Notable points for the right plane */
-  protected final GeoPoint[] rightPlanePoints;
-
-  /** Center point */
-  protected final GeoPoint centerPoint;
-
-  /** Composite left/right bounds */
-  protected final EitherBound eitherBound;
-
-  /** A point on the edge */
-  protected final GeoPoint[] edgePoints;
-
-  /**
-   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}.
-   * Horizontal angle must be greater than or equal to PI.
-   */
-  public GeoWideNorthRectangle(final PlanetModel planetModel, final double bottomLat, final double leftLon, double rightLon) {
-    super(planetModel);
-    // Argument checking
-    if (bottomLat > Math.PI * 0.5 || bottomLat < -Math.PI * 0.5)
-      throw new IllegalArgumentException("Bottom latitude out of range");
-    if (leftLon < -Math.PI || leftLon > Math.PI)
-      throw new IllegalArgumentException("Left longitude out of range");
-    if (rightLon < -Math.PI || rightLon > Math.PI)
-      throw new IllegalArgumentException("Right longitude out of range");
-    double extent = rightLon - leftLon;
-    if (extent < 0.0) {
-      extent += 2.0 * Math.PI;
-    }
-    if (extent < Math.PI)
-      throw new IllegalArgumentException("Width of rectangle too small");
-
-    this.bottomLat = bottomLat;
-    this.leftLon = leftLon;
-    this.rightLon = rightLon;
-
-    final double sinBottomLat = Math.sin(bottomLat);
-    final double cosBottomLat = Math.cos(bottomLat);
-    final double sinLeftLon = Math.sin(leftLon);
-    final double cosLeftLon = Math.cos(leftLon);
-    final double sinRightLon = Math.sin(rightLon);
-    final double cosRightLon = Math.cos(rightLon);
-
-    // Now build the four points
-    this.LRHC = new GeoPoint(planetModel, sinBottomLat, sinRightLon, cosBottomLat, cosRightLon, bottomLat, rightLon);
-    this.LLHC = new GeoPoint(planetModel, sinBottomLat, sinLeftLon, cosBottomLat, cosLeftLon, bottomLat, leftLon);
-
-    final double middleLat = (Math.PI * 0.5 + bottomLat) * 0.5;
-    final double sinMiddleLat = Math.sin(middleLat);
-    this.cosMiddleLat = Math.cos(middleLat);
-    // Normalize
-    while (leftLon > rightLon) {
-      rightLon += Math.PI * 2.0;
-    }
-    final double middleLon = (leftLon + rightLon) * 0.5;
-    final double sinMiddleLon = Math.sin(middleLon);
-    final double cosMiddleLon = Math.cos(middleLon);
-
-    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinMiddleLon, cosMiddleLat, cosMiddleLon);
-
-    this.bottomPlane = new SidedPlane(centerPoint, planetModel, sinBottomLat);
-    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
-    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
-
-    this.bottomPlanePoints = new GeoPoint[]{LLHC, LRHC};
-    this.leftPlanePoints = new GeoPoint[]{planetModel.NORTH_POLE, LLHC};
-    this.rightPlanePoints = new GeoPoint[]{planetModel.NORTH_POLE, LRHC};
-
-    this.eitherBound = new EitherBound();
-    this.edgePoints = new GeoPoint[]{planetModel.NORTH_POLE};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    final double newTopLat = Math.PI * 0.5;
-    final double newBottomLat = bottomLat - angle;
-    // Figuring out when we escalate to a special case requires some prefiguring
-    double currentLonSpan = rightLon - leftLon;
-    if (currentLonSpan < 0.0)
-      currentLonSpan += Math.PI * 2.0;
-    double newLeftLon = leftLon - angle;
-    double newRightLon = rightLon + angle;
-    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
-      newLeftLon = -Math.PI;
-      newRightLon = Math.PI;
-    }
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return
-        bottomPlane.isWithin(x, y, z) &&
-            (leftPlane.isWithin(x, y, z) ||
-                rightPlane.isWithin(x, y, z));
-  }
-
-  @Override
-  public double getRadius() {
-    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
-    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
-    // the distance to the right or left edge from the center.
-    final double centerAngle = (rightLon - (rightLon + leftLon) * 0.5) * cosMiddleLat;
-    final double bottomAngle = centerPoint.arcDistance(LLHC);
-    return Math.max(centerAngle, bottomAngle);
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    return centerPoint;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    // Right and left bounds are essentially independent hemispheres; crossing into the wrong part of one
-    // requires crossing into the right part of the other.  So intersection can ignore the left/right bounds.
-    return
-        p.intersects(planetModel, bottomPlane, notablePoints, bottomPlanePoints, bounds, eitherBound) ||
-            p.intersects(planetModel, leftPlane, notablePoints, leftPlanePoints, bounds, bottomPlane) ||
-            p.intersects(planetModel, rightPlane, notablePoints, rightPlanePoints, bounds, bottomPlane);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds.isWide()
-      .addHorizontalPlane(planetModel, bottomLat, bottomPlane, eitherBound)
-      .addVerticalPlane(planetModel, leftLon, leftPlane, bottomPlane)
-      .addVerticalPlane(planetModel, rightLon, rightPlane, bottomPlane)
-      .addPoint(LLHC).addPoint(LRHC).addPoint(planetModel.NORTH_POLE);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    //System.err.println(this+" comparing to "+path);
-    final int insideRectangle = isShapeInsideBBox(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some inside");
-      return OVERLAPS;
-    }
-
-    final boolean insideShape = path.isWithin(planetModel.NORTH_POLE);
-
-    if (insideRectangle == ALL_INSIDE && insideShape) {
-      //System.err.println(" both inside each other");
-      return OVERLAPS;
-    }
-
-    if (
-        path.intersects(bottomPlane, bottomPlanePoints, eitherBound) ||
-            path.intersects(leftPlane, leftPlanePoints, bottomPlane) ||
-            path.intersects(rightPlane, rightPlanePoints, bottomPlane)) {
-      //System.err.println(" edges intersect");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      //System.err.println(" shape inside rectangle");
-      return WITHIN;
-    }
-
-    if (insideShape) {
-      //System.err.println(" rectangle inside shape");
-      return CONTAINS;
-    }
-
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    final double bottomDistance = distanceStyle.computeDistance(planetModel, bottomPlane, x,y,z, eitherBound);
-    // Because the rectangle exceeds 180 degrees, it is safe to compute the horizontally 
-    // unbounded distance to both the left and the right and only take the minimum of the two.
-    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, bottomPlane);
-    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, bottomPlane);
-    
-    final double LRHCDistance = distanceStyle.computeDistance(LRHC, x,y,z);
-    final double LLHCDistance = distanceStyle.computeDistance(LLHC, x,y,z);
-    
-    return Math.min(
-      Math.min(
-        bottomDistance,
-        Math.min(leftDistance, rightDistance)),
-      Math.min(LRHCDistance, LLHCDistance));
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoWideNorthRectangle))
-      return false;
-    GeoWideNorthRectangle other = (GeoWideNorthRectangle) o;
-    return super.equals(other) && other.LLHC.equals(LLHC) && other.LRHC.equals(LRHC);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + LLHC.hashCode();
-    result = 31 * result + LRHC.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoWideNorthRectangle: {planetmodel="+planetModel+", bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
-  }
-
-  /** Membership implementation representing a wide (more than 180 degree) bound.
-   */
-  protected class EitherBound implements Membership {
-    /** Constructor.
-     */
-    public EitherBound() {
-    }
-
-    @Override
-    public boolean isWithin(final Vector v) {
-      return leftPlane.isWithin(v) || rightPlane.isWithin(v);
-    }
-
-    @Override
-    public boolean isWithin(final double x, final double y, final double z) {
-      return leftPlane.isWithin(x, y, z) || rightPlane.isWithin(x, y, z);
-    }
-  }
-}
-  
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideRectangle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideRectangle.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideRectangle.java
deleted file mode 100755
index 68397bb..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideRectangle.java
+++ /dev/null
@@ -1,319 +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.geo3d;
-
-/**
- * Bounding box wider than PI but limited on four sides (top lat,
- * bottom lat, left lon, right lon).
- *
- * @lucene.internal
- */
-public class GeoWideRectangle extends GeoBaseBBox {
-  /** The top latitude */
-  protected final double topLat;
-  /** The bottom latitude */
-  protected final double bottomLat;
-  /** The left longitude */
-  protected final double leftLon;
-  /** The right longitude */
-  protected final double rightLon;
-
-  /** Cosine of the middle latitude */
-  protected final double cosMiddleLat;
-
-  /** Upper left hand corner point */
-  protected final GeoPoint ULHC;
-  /** Lower right hand corner point */
-  protected final GeoPoint URHC;
-  /** Lower right hand corner point */
-  protected final GeoPoint LRHC;
-  /** Lower left hand corner point */
-  protected final GeoPoint LLHC;
-
-  /** Top plane */
-  protected final SidedPlane topPlane;
-  /** Bottom plane */
-  protected final SidedPlane bottomPlane;
-  /** Left plane */
-  protected final SidedPlane leftPlane;
-  /** Right plane */
-  protected final SidedPlane rightPlane;
-
-  /** Top plane's notable points */
-  protected final GeoPoint[] topPlanePoints;
-  /** Bottom plane's notable points */
-  protected final GeoPoint[] bottomPlanePoints;
-  /** Left plane's notable points */
-  protected final GeoPoint[] leftPlanePoints;
-  /** Right plane's notable points */
-  protected final GeoPoint[] rightPlanePoints;
-
-  /** Center point */
-  protected final GeoPoint centerPoint;
-
-  /** Combined left/right bounds */
-  protected final EitherBound eitherBound;
-
-  /** A point on the edge */
-  protected final GeoPoint[] edgePoints;
-
-  /**
-   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}.
-   * Horizontal angle must be greater than or equal to PI.
-   */
-  public GeoWideRectangle(final PlanetModel planetModel, final double topLat, final double bottomLat, final double leftLon, double rightLon) {
-    super(planetModel);
-    // Argument checking
-    if (topLat > Math.PI * 0.5 || topLat < -Math.PI * 0.5)
-      throw new IllegalArgumentException("Top latitude out of range");
-    if (bottomLat > Math.PI * 0.5 || bottomLat < -Math.PI * 0.5)
-      throw new IllegalArgumentException("Bottom latitude out of range");
-    if (topLat < bottomLat)
-      throw new IllegalArgumentException("Top latitude less than bottom latitude");
-    if (leftLon < -Math.PI || leftLon > Math.PI)
-      throw new IllegalArgumentException("Left longitude out of range");
-    if (rightLon < -Math.PI || rightLon > Math.PI)
-      throw new IllegalArgumentException("Right longitude out of range");
-    double extent = rightLon - leftLon;
-    if (extent < 0.0) {
-      extent += 2.0 * Math.PI;
-    }
-    if (extent < Math.PI)
-      throw new IllegalArgumentException("Width of rectangle too small");
-
-    this.topLat = topLat;
-    this.bottomLat = bottomLat;
-    this.leftLon = leftLon;
-    this.rightLon = rightLon;
-
-    final double sinTopLat = Math.sin(topLat);
-    final double cosTopLat = Math.cos(topLat);
-    final double sinBottomLat = Math.sin(bottomLat);
-    final double cosBottomLat = Math.cos(bottomLat);
-    final double sinLeftLon = Math.sin(leftLon);
-    final double cosLeftLon = Math.cos(leftLon);
-    final double sinRightLon = Math.sin(rightLon);
-    final double cosRightLon = Math.cos(rightLon);
-
-    // Now build the four points
-    this.ULHC = new GeoPoint(planetModel, sinTopLat, sinLeftLon, cosTopLat, cosLeftLon, topLat, leftLon);
-    this.URHC = new GeoPoint(planetModel, sinTopLat, sinRightLon, cosTopLat, cosRightLon, topLat, rightLon);
-    this.LRHC = new GeoPoint(planetModel, sinBottomLat, sinRightLon, cosBottomLat, cosRightLon, bottomLat, rightLon);
-    this.LLHC = new GeoPoint(planetModel, sinBottomLat, sinLeftLon, cosBottomLat, cosLeftLon, bottomLat, leftLon);
-
-    final double middleLat = (topLat + bottomLat) * 0.5;
-    final double sinMiddleLat = Math.sin(middleLat);
-    this.cosMiddleLat = Math.cos(middleLat);
-    // Normalize
-    while (leftLon > rightLon) {
-      rightLon += Math.PI * 2.0;
-    }
-    final double middleLon = (leftLon + rightLon) * 0.5;
-    final double sinMiddleLon = Math.sin(middleLon);
-    final double cosMiddleLon = Math.cos(middleLon);
-
-    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinMiddleLon, cosMiddleLat, cosMiddleLon);
-
-    this.topPlane = new SidedPlane(centerPoint, planetModel, sinTopLat);
-    this.bottomPlane = new SidedPlane(centerPoint, planetModel, sinBottomLat);
-    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
-    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
-
-    this.topPlanePoints = new GeoPoint[]{ULHC, URHC};
-    this.bottomPlanePoints = new GeoPoint[]{LLHC, LRHC};
-    this.leftPlanePoints = new GeoPoint[]{ULHC, LLHC};
-    this.rightPlanePoints = new GeoPoint[]{URHC, LRHC};
-
-    this.eitherBound = new EitherBound();
-
-    this.edgePoints = new GeoPoint[]{ULHC};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    final double newTopLat = topLat + angle;
-    final double newBottomLat = bottomLat - angle;
-    // Figuring out when we escalate to a special case requires some prefiguring
-    double currentLonSpan = rightLon - leftLon;
-    if (currentLonSpan < 0.0)
-      currentLonSpan += Math.PI * 2.0;
-    double newLeftLon = leftLon - angle;
-    double newRightLon = rightLon + angle;
-    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
-      newLeftLon = -Math.PI;
-      newRightLon = Math.PI;
-    }
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return topPlane.isWithin(x, y, z) &&
-        bottomPlane.isWithin(x, y, z) &&
-        (leftPlane.isWithin(x, y, z) ||
-            rightPlane.isWithin(x, y, z));
-  }
-
-  @Override
-  public double getRadius() {
-    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
-    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
-    // the distance to the right or left edge from the center.
-    final double centerAngle = (rightLon - (rightLon + leftLon) * 0.5) * cosMiddleLat;
-    final double topAngle = centerPoint.arcDistance(URHC);
-    final double bottomAngle = centerPoint.arcDistance(LLHC);
-    return Math.max(centerAngle, Math.max(topAngle, bottomAngle));
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  /**
-   * Returns the center of a circle into which the area will be inscribed.
-   *
-   * @return the center.
-   */
-  @Override
-  public GeoPoint getCenter() {
-    return centerPoint;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    // Right and left bounds are essentially independent hemispheres; crossing into the wrong part of one
-    // requires crossing into the right part of the other.  So intersection can ignore the left/right bounds.
-    return p.intersects(planetModel, topPlane, notablePoints, topPlanePoints, bounds, bottomPlane, eitherBound) ||
-        p.intersects(planetModel, bottomPlane, notablePoints, bottomPlanePoints, bounds, topPlane, eitherBound) ||
-        p.intersects(planetModel, leftPlane, notablePoints, leftPlanePoints, bounds, topPlane, bottomPlane) ||
-        p.intersects(planetModel, rightPlane, notablePoints, rightPlanePoints, bounds, topPlane, bottomPlane);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds.isWide()
-      .addHorizontalPlane(planetModel, topLat, topPlane, bottomPlane, eitherBound)
-      .addVerticalPlane(planetModel, rightLon, rightPlane, topPlane, bottomPlane)
-      .addHorizontalPlane(planetModel, bottomLat, bottomPlane, topPlane, eitherBound)
-      .addVerticalPlane(planetModel, leftLon, leftPlane, topPlane, bottomPlane)
-      .addPoint(ULHC).addPoint(URHC).addPoint(LRHC).addPoint(LLHC);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    //System.err.println(this+" comparing to "+path);
-    final int insideRectangle = isShapeInsideBBox(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some inside");
-      return OVERLAPS;
-    }
-
-    final boolean insideShape = path.isWithin(ULHC);
-
-    if (insideRectangle == ALL_INSIDE && insideShape) {
-      //System.err.println(" both inside each other");
-      return OVERLAPS;
-    }
-
-    if (path.intersects(topPlane, topPlanePoints, bottomPlane, eitherBound) ||
-        path.intersects(bottomPlane, bottomPlanePoints, topPlane, eitherBound) ||
-        path.intersects(leftPlane, leftPlanePoints, topPlane, bottomPlane) ||
-        path.intersects(rightPlane, rightPlanePoints, topPlane, bottomPlane)) {
-      //System.err.println(" edges intersect");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      //System.err.println(" shape inside rectangle");
-      return WITHIN;
-    }
-
-    if (insideShape) {
-      //System.err.println(" rectangle inside shape");
-      return CONTAINS;
-    }
-
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    final double topDistance = distanceStyle.computeDistance(planetModel, topPlane, x,y,z, bottomPlane, eitherBound);
-    final double bottomDistance = distanceStyle.computeDistance(planetModel, bottomPlane, x,y,z, topPlane, eitherBound);
-    // Because the rectangle exceeds 180 degrees, it is safe to compute the horizontally 
-    // unbounded distance to both the left and the right and only take the minimum of the two.
-    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, topPlane, bottomPlane);
-    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, topPlane, bottomPlane);
-    
-    final double ULHCDistance = distanceStyle.computeDistance(ULHC, x,y,z);
-    final double URHCDistance = distanceStyle.computeDistance(URHC, x,y,z);
-    final double LRHCDistance = distanceStyle.computeDistance(LRHC, x,y,z);
-    final double LLHCDistance = distanceStyle.computeDistance(LLHC, x,y,z);
-    
-    return Math.min(
-      Math.min(
-        Math.min(topDistance, bottomDistance),
-        Math.min(leftDistance, rightDistance)),
-      Math.min(
-        Math.min(ULHCDistance, URHCDistance),
-        Math.min(LRHCDistance, LLHCDistance)));
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoWideRectangle))
-      return false;
-    GeoWideRectangle other = (GeoWideRectangle) o;
-    return super.equals(other) && other.ULHC.equals(ULHC) && other.LRHC.equals(LRHC);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + ULHC.hashCode();
-    result = 31 * result + LRHC.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoWideRectangle: {planetmodel=" + planetModel + ", toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + "), bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
-  }
-
-  /** A membership implementation representing a wide (more than 180) left/right bound.
-   */
-  protected class EitherBound implements Membership {
-    /** Constructor.
-      */
-    public EitherBound() {
-    }
-
-    @Override
-    public boolean isWithin(final Vector v) {
-      return leftPlane.isWithin(v) || rightPlane.isWithin(v);
-    }
-
-    @Override
-    public boolean isWithin(final double x, final double y, final double z) {
-      return leftPlane.isWithin(x, y, z) || rightPlane.isWithin(x, y, z);
-    }
-  }
-}
-  

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideSouthRectangle.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideSouthRectangle.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideSouthRectangle.java
deleted file mode 100644
index 8bd7220..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWideSouthRectangle.java
+++ /dev/null
@@ -1,284 +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.geo3d;
-
-/**
- * Bounding box wider than PI but limited on three sides (top lat,
- * left lon, right lon).
- *
- * @lucene.internal
- */
-public class GeoWideSouthRectangle extends GeoBaseBBox {
-  /** Top latitude of rect */
-  protected final double topLat;
-  /** Left longitude of rect */
-  protected final double leftLon;
-  /** Right longitude of rect */
-  protected final double rightLon;
-
-  /** Cosine of middle latitude */
-  protected final double cosMiddleLat;
-
-  /** Upper left hand corner */
-  protected final GeoPoint ULHC;
-  /** Upper right hand corner */
-  protected final GeoPoint URHC;
-
-  /** The top plane */
-  protected final SidedPlane topPlane;
-  /** The left plane */
-  protected final SidedPlane leftPlane;
-  /** The right plane */
-  protected final SidedPlane rightPlane;
-
-  /** Notable points for top plane */
-  protected final GeoPoint[] topPlanePoints;
-  /** Notable points for left plane */
-  protected final GeoPoint[] leftPlanePoints;
-  /** Notable points for right plane */
-  protected final GeoPoint[] rightPlanePoints;
-
-  /** Center point */
-  protected final GeoPoint centerPoint;
-
-  /** Left/right bounds */
-  protected final EitherBound eitherBound;
-
-  /** A point on the edge */
-  protected final GeoPoint[] edgePoints;
-
-  /**
-   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}.
-   * Horizontal angle must be greater than or equal to PI.
-   */
-  public GeoWideSouthRectangle(final PlanetModel planetModel, final double topLat, final double leftLon, double rightLon) {
-    super(planetModel);
-    // Argument checking
-    if (topLat > Math.PI * 0.5 || topLat < -Math.PI * 0.5)
-      throw new IllegalArgumentException("Top latitude out of range");
-    if (leftLon < -Math.PI || leftLon > Math.PI)
-      throw new IllegalArgumentException("Left longitude out of range");
-    if (rightLon < -Math.PI || rightLon > Math.PI)
-      throw new IllegalArgumentException("Right longitude out of range");
-    double extent = rightLon - leftLon;
-    if (extent < 0.0) {
-      extent += 2.0 * Math.PI;
-    }
-    if (extent < Math.PI)
-      throw new IllegalArgumentException("Width of rectangle too small");
-
-    this.topLat = topLat;
-    this.leftLon = leftLon;
-    this.rightLon = rightLon;
-
-    final double sinTopLat = Math.sin(topLat);
-    final double cosTopLat = Math.cos(topLat);
-    final double sinLeftLon = Math.sin(leftLon);
-    final double cosLeftLon = Math.cos(leftLon);
-    final double sinRightLon = Math.sin(rightLon);
-    final double cosRightLon = Math.cos(rightLon);
-
-    // Now build the four points
-    this.ULHC = new GeoPoint(planetModel, sinTopLat, sinLeftLon, cosTopLat, cosLeftLon, topLat, leftLon);
-    this.URHC = new GeoPoint(planetModel, sinTopLat, sinRightLon, cosTopLat, cosRightLon, topLat, rightLon);
-
-    final double middleLat = (topLat - Math.PI * 0.5) * 0.5;
-    final double sinMiddleLat = Math.sin(middleLat);
-    this.cosMiddleLat = Math.cos(middleLat);
-    // Normalize
-    while (leftLon > rightLon) {
-      rightLon += Math.PI * 2.0;
-    }
-    final double middleLon = (leftLon + rightLon) * 0.5;
-    final double sinMiddleLon = Math.sin(middleLon);
-    final double cosMiddleLon = Math.cos(middleLon);
-
-    this.centerPoint = new GeoPoint(planetModel, sinMiddleLat, sinMiddleLon, cosMiddleLat, cosMiddleLon);
-
-    this.topPlane = new SidedPlane(centerPoint, planetModel, sinTopLat);
-    this.leftPlane = new SidedPlane(centerPoint, cosLeftLon, sinLeftLon);
-    this.rightPlane = new SidedPlane(centerPoint, cosRightLon, sinRightLon);
-
-    this.topPlanePoints = new GeoPoint[]{ULHC, URHC};
-    this.leftPlanePoints = new GeoPoint[]{ULHC, planetModel.SOUTH_POLE};
-    this.rightPlanePoints = new GeoPoint[]{URHC, planetModel.SOUTH_POLE};
-
-    this.eitherBound = new EitherBound();
-    
-    this.edgePoints = new GeoPoint[]{planetModel.SOUTH_POLE};
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    final double newTopLat = topLat + angle;
-    final double newBottomLat = -Math.PI * 0.5;
-    // Figuring out when we escalate to a special case requires some prefiguring
-    double currentLonSpan = rightLon - leftLon;
-    if (currentLonSpan < 0.0)
-      currentLonSpan += Math.PI * 2.0;
-    double newLeftLon = leftLon - angle;
-    double newRightLon = rightLon + angle;
-    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
-      newLeftLon = -Math.PI;
-      newRightLon = Math.PI;
-    }
-    return GeoBBoxFactory.makeGeoBBox(planetModel, newTopLat, newBottomLat, newLeftLon, newRightLon);
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return topPlane.isWithin(x, y, z) &&
-        (leftPlane.isWithin(x, y, z) ||
-            rightPlane.isWithin(x, y, z));
-  }
-
-  @Override
-  public double getRadius() {
-    // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
-    // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
-    // the distance to the right or left edge from the center.
-    final double centerAngle = (rightLon - (rightLon + leftLon) * 0.5) * cosMiddleLat;
-    final double topAngle = centerPoint.arcDistance(URHC);
-    return Math.max(centerAngle, topAngle);
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    return centerPoint;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    // Right and left bounds are essentially independent hemispheres; crossing into the wrong part of one
-    // requires crossing into the right part of the other.  So intersection can ignore the left/right bounds.
-    return p.intersects(planetModel, topPlane, notablePoints, topPlanePoints, bounds, eitherBound) ||
-        p.intersects(planetModel, leftPlane, notablePoints, leftPlanePoints, bounds, topPlane) ||
-        p.intersects(planetModel, rightPlane, notablePoints, rightPlanePoints, bounds, topPlane);
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    bounds.isWide()
-      .addHorizontalPlane(planetModel, topLat, topPlane, eitherBound)
-      .addVerticalPlane(planetModel, rightLon, rightPlane, topPlane)
-      .addVerticalPlane(planetModel, leftLon, leftPlane, topPlane)
-      .addPoint(ULHC).addPoint(URHC).addPoint(planetModel.SOUTH_POLE);
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    //System.err.println(this+" comparing to "+path);
-    final int insideRectangle = isShapeInsideBBox(path);
-    if (insideRectangle == SOME_INSIDE) {
-      //System.err.println(" some inside");
-      return OVERLAPS;
-    }
-
-    final boolean insideShape = path.isWithin(planetModel.SOUTH_POLE);
-
-    if (insideRectangle == ALL_INSIDE && insideShape) {
-      //System.err.println(" both inside each other");
-      return OVERLAPS;
-    }
-
-    if (path.intersects(topPlane, topPlanePoints, eitherBound) ||
-        path.intersects(leftPlane, leftPlanePoints, topPlane) ||
-        path.intersects(rightPlane, rightPlanePoints, topPlane)) {
-      //System.err.println(" edges intersect");
-      return OVERLAPS;
-    }
-
-    if (insideRectangle == ALL_INSIDE) {
-      //System.err.println(" shape inside rectangle");
-      return WITHIN;
-    }
-
-    if (insideShape) {
-      //System.err.println(" rectangle inside shape");
-      return CONTAINS;
-    }
-
-    //System.err.println(" disjoint");
-    return DISJOINT;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    final double topDistance = distanceStyle.computeDistance(planetModel, topPlane, x,y,z, eitherBound);
-    // Because the rectangle exceeds 180 degrees, it is safe to compute the horizontally 
-    // unbounded distance to both the left and the right and only take the minimum of the two.
-    final double leftDistance = distanceStyle.computeDistance(planetModel, leftPlane, x,y,z, topPlane);
-    final double rightDistance = distanceStyle.computeDistance(planetModel, rightPlane, x,y,z, topPlane);
-    
-    final double ULHCDistance = distanceStyle.computeDistance(ULHC, x,y,z);
-    final double URHCDistance = distanceStyle.computeDistance(URHC, x,y,z);
-    
-    return Math.min(
-      Math.min(
-        topDistance,
-        Math.min(leftDistance, rightDistance)),
-      Math.min(ULHCDistance, URHCDistance));
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoWideSouthRectangle))
-      return false;
-    GeoWideSouthRectangle other = (GeoWideSouthRectangle) o;
-    return super.equals(o) && other.ULHC.equals(ULHC) && other.URHC.equals(URHC);
-  }
-
-  @Override
-  public int hashCode() {
-    int result = super.hashCode();
-    result = 31 * result + ULHC.hashCode();
-    result = 31 * result + URHC.hashCode();
-    return result;
-  }
-
-  @Override
-  public String toString() {
-    return "GeoWideSouthRectangle: {planetmodel="+planetModel+", toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + "), leftlon=" + leftLon + "(" + leftLon * 180.0 / Math.PI + "), rightlon=" + rightLon + "(" + rightLon * 180.0 / Math.PI + ")}";
-  }
-
-  /** Membership implementation representing width more than 180.
-   */
-  protected class EitherBound implements Membership {
-    /** Constructor.
-     */
-    public EitherBound() {
-    }
-
-    @Override
-    public boolean isWithin(final Vector v) {
-      return leftPlane.isWithin(v) || rightPlane.isWithin(v);
-    }
-
-    @Override
-    public boolean isWithin(final double x, final double y, final double z) {
-      return leftPlane.isWithin(x, y, z) || rightPlane.isWithin(x, y, z);
-    }
-  }
-}
-  
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWorld.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWorld.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWorld.java
deleted file mode 100755
index 35ec4ae..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoWorld.java
+++ /dev/null
@@ -1,106 +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.geo3d;
-
-/**
- * Bounding box including the entire world.
- *
- * @lucene.internal
- */
-public class GeoWorld extends GeoBaseBBox {
-  /** No points on the edge of the shape */
-  protected final static GeoPoint[] edgePoints = new GeoPoint[0];
-  /** Point in the middle of the world */
-  protected final GeoPoint originPoint;
-  
-  /** Constructor.
-   *@param planetModel is the planet model.
-   */
-  public GeoWorld(final PlanetModel planetModel) {
-    super(planetModel);
-    originPoint = new GeoPoint(planetModel.ab, 1.0, 0.0, 0.0);
-  }
-
-  @Override
-  public GeoBBox expand(final double angle) {
-    return this;
-  }
-
-  @Override
-  public double getRadius() {
-    return Math.PI;
-  }
-
-  @Override
-  public GeoPoint getCenter() {
-    // Totally arbitrary
-    return originPoint;
-  }
-
-  @Override
-  public boolean isWithin(final double x, final double y, final double z) {
-    return true;
-  }
-
-  @Override
-  public GeoPoint[] getEdgePoints() {
-    return edgePoints;
-  }
-
-  @Override
-  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    return false;
-  }
-
-  @Override
-  public void getBounds(Bounds bounds) {
-    super.getBounds(bounds);
-    // Unnecessary
-    //bounds.noLongitudeBound().noTopLatitudeBound().noBottomLatitudeBound();
-  }
-
-  @Override
-  public int getRelationship(final GeoShape path) {
-    if (path.getEdgePoints().length > 0)
-      // Path is always within the world
-      return WITHIN;
-
-    return OVERLAPS;
-  }
-
-  @Override
-  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    return 0.0;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (!(o instanceof GeoWorld))
-      return false;
-    return super.equals(o);
-  }
-
-  @Override
-  public int hashCode() {
-    return super.hashCode();
-  }
-
-  @Override
-  public String toString() {
-    return "GeoWorld: {planetmodel="+planetModel+"}";
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a31a8c7/lucene/spatial3d/src/java/org/apache/lucene/geo3d/LatLonBounds.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/LatLonBounds.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/LatLonBounds.java
deleted file mode 100644
index 6478e0c..0000000
--- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/LatLonBounds.java
+++ /dev/null
@@ -1,322 +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.geo3d;
-
-/**
- * An object for accumulating latitude/longitude bounds information.
- *
- * @lucene.experimental
- */
-public class LatLonBounds implements Bounds {
-
-  /** Set to true if no longitude bounds can be stated */
-  protected boolean noLongitudeBound = false;
-  /** Set to true if no top latitude bound can be stated */
-  protected boolean noTopLatitudeBound = false;
-  /** Set to true if no bottom latitude bound can be stated */
-  protected boolean noBottomLatitudeBound = false;
-
-  /** If non-null, the minimum latitude bound */
-  protected Double minLatitude = null;
-  /** If non-null, the maximum latitude bound */
-  protected Double maxLatitude = null;
-
-  // For longitude bounds, this class needs to worry about keeping track of the distinction
-  // between left-side bounds and right-side bounds.  Points are always submitted in pairs
-  // which have a maximum longitude separation of Math.PI.  It's therefore always possible
-  // to determine which point represents a left bound, and which point represents a right
-  // bound.
-  //
-  // The next problem is how to compare two of the same kind of bound, e.g. two left bounds.
-  // We need to keep track of the leftmost longitude of the shape, but since this is a circle,
-  // this is arbitrary.  What we could try to do instead would be to find a pair of (left,right) bounds such
-  // that:
-  // (1) all other bounds are within, and
-  // (2) the left minus right distance is minimized
-  // Unfortunately, there are still shapes that cannot be summarized in this way correctly.
-  // For example. consider a spiral that entirely circles the globe; we might arbitrarily choose
-  // lat/lon bounds that do not in fact circle the globe.
-  //
-  // One way to handle the longitude issue correctly is therefore to stipulate that we
-  // walk the bounds of the shape in some kind of connected order.  Each point or circle is therefore
-  // added in a sequence.  We also need an interior point to make sure we have the right
-  // choice of longitude bounds.  But even with this, we still can't always choose whether the actual shape
-  // goes right or left.
-  //
-  // We can make the specification truly general by submitting the following in order:
-  // addSide(PlaneSide side, Membership... constraints)
-  // ...
-  // This is unambiguous, but I still can't see yet how this would help compute the bounds.  The plane
-  // solution would in general seem to boil down to the same logic that relies on points along the path
-  // to define the shape boundaries.  I guess the one thing that you do know for a bounded edge is that
-  // the endpoints are actually connected.  But it is not clear whether relationship helps in any way.
-  //
-  // In any case, if we specify shapes by a sequence of planes, we should stipulate that multiple sequences
-  // are allowed, provided they progressively tile an area of the sphere that is connected and sequential.
-  // For example, paths do alternating rectangles and circles, in sequence.  Each sequence member is
-  // described by a sequence of planes.  I think it would also be reasonable to insist that the first segment
-  // of a shape overlap or adjoin the previous shape.
-  //
-  // Here's a way to think about it that might help: Traversing every edge should grow the longitude bounds
-  // in the direction of the traversal.  So if the traversal is always known to be less than PI in total longitude
-  // angle, then it is possible to use the endpoints to determine the unambiguous extension of the envelope.
-  // For example, say you are currently at longitude -0.5.  The next point is at longitude PI-0.1.  You could say
-  // that the difference in longitude going one way around would be beter than the distance the other way
-  // around, and therefore the longitude envelope should be extended accordingly.  But in practice, when an
-  // edge goes near a pole and may be inclined as well, the longer longitude change might be the right path, even
-  // if the arc length is short.  So this too doesn't work.
-  //
-  // Given we have a hard time making an exact match, here's the current proposal.  The proposal is a
-  // heuristic, based on the idea that most areas are small compared to the circumference of the globe.
-  // We keep track of the last point we saw, and take each point as it arrives, and compute its longitude.
-  // Then, we have a choice as to which way to expand the envelope: we can expand by going to the left or
-  // to the right.  We choose the direction with the least longitude difference.  (If we aren't sure,
-  // and can recognize that, we can set "unconstrained in longitude".)
-
-  /** If non-null, the left longitude bound */
-  protected Double leftLongitude = null;
-  /** If non-null, the right longitude bound */
-  protected Double rightLongitude = null;
-
-  /** Construct an empty bounds object */
-  public LatLonBounds() {
-  }
-
-  // Accessor methods
-  
-  /** Get maximum latitude, if any.
-   *@return maximum latitude or null.
-   */
-  public Double getMaxLatitude() {
-    return maxLatitude;
-  }
-
-  /** Get minimum latitude, if any.
-   *@return minimum latitude or null.
-   */
-  public Double getMinLatitude() {
-    return minLatitude;
-  }
-
-  /** Get left longitude, if any.
-   *@return left longitude, or null.
-   */
-  public Double getLeftLongitude() {
-    return leftLongitude;
-  }
-
-  /** Get right longitude, if any.
-   *@return right longitude, or null.
-   */
-  public Double getRightLongitude() {
-    return rightLongitude;
-  }
-
-  // Degenerate case check
-  
-  /** Check if there's no longitude bound.
-   *@return true if no longitude bound.
-   */
-  public boolean checkNoLongitudeBound() {
-    return noLongitudeBound;
-  }
-
-  /** Check if there's no top latitude bound.
-   *@return true if no top latitude bound.
-   */
-  public boolean checkNoTopLatitudeBound() {
-    return noTopLatitudeBound;
-  }
-
-  /** Check if there's no bottom latitude bound.
-   *@return true if no bottom latitude bound.
-   */
-  public boolean checkNoBottomLatitudeBound() {
-    return noBottomLatitudeBound;
-  }
-
-  // Modification methods
-  
-  @Override
-  public Bounds addPlane(final PlanetModel planetModel, final Plane plane, final Membership... bounds) {
-    plane.recordBounds(planetModel, this, bounds);
-    return this;
-  }
-
-  @Override
-  public Bounds addHorizontalPlane(final PlanetModel planetModel,
-    final double latitude,
-    final Plane horizontalPlane,
-    final Membership... bounds) {
-    if (!noTopLatitudeBound || !noBottomLatitudeBound) {
-      addLatitudeBound(latitude);
-    }
-    return this;
-  }
-    
-  @Override
-  public Bounds addVerticalPlane(final PlanetModel planetModel,
-    final double longitude,
-    final Plane verticalPlane,
-    final Membership... bounds) {
-    if (!noLongitudeBound) {
-      addLongitudeBound(longitude);
-    }
-    return this;
-  }
-
-  @Override
-  public Bounds isWide() {
-    return noLongitudeBound();
-  }
-
-  @Override
-  public Bounds addXValue(final GeoPoint point) {
-    if (!noLongitudeBound) {
-      // Get a longitude value
-      addLongitudeBound(point.getLongitude());
-    }
-    return this;
-  }
-
-  @Override
-  public Bounds addYValue(final GeoPoint point) {
-    if (!noLongitudeBound) {
-      // Get a longitude value
-      addLongitudeBound(point.getLongitude());
-    }
-    return this;
-  }
-
-  @Override
-  public Bounds addZValue(final GeoPoint point) {
-    if (!noTopLatitudeBound || !noBottomLatitudeBound) {
-      // Compute a latitude value
-      double latitude = point.getLatitude();
-      addLatitudeBound(latitude);
-    }
-    return this;
-  }
-
-  @Override
-  public Bounds addPoint(GeoPoint point) {
-    if (!noLongitudeBound) {
-      // Get a longitude value
-      addLongitudeBound(point.getLongitude());
-    }
-    if (!noTopLatitudeBound || !noBottomLatitudeBound) {
-      // Compute a latitude value
-      addLatitudeBound(point.getLatitude());
-    }
-    return this;
-  }
-  
-  @Override
-  public Bounds noLongitudeBound() {
-    noLongitudeBound = true;
-    leftLongitude = null;
-    rightLongitude = null;
-    return this;
-  }
-
-  @Override
-  public Bounds noTopLatitudeBound() {
-    noTopLatitudeBound = true;
-    maxLatitude = null;
-    return this;
-  }
-
-  @Override
-  public Bounds noBottomLatitudeBound() {
-    noBottomLatitudeBound = true;
-    minLatitude = null;
-    return this;
-  }
-
-  // Protected methods
-  
-  /** Update latitude bound.
-   *@param latitude is the latitude.
-   */
-  protected void addLatitudeBound(double latitude) {
-    if (!noTopLatitudeBound && (maxLatitude == null || latitude > maxLatitude))
-      maxLatitude = latitude;
-    if (!noBottomLatitudeBound && (minLatitude == null || latitude < minLatitude))
-      minLatitude = latitude;
-  }
-
-  /** Update longitude bound.
-   *@param longitude is the new longitude value.
-   */
-  protected void addLongitudeBound(double longitude) {
-    // If this point is within the current bounds, we're done; otherwise
-    // expand one side or the other.
-    if (leftLongitude == null && rightLongitude == null) {
-      leftLongitude = longitude;
-      rightLongitude = longitude;
-    } else {
-      // Compute whether we're to the right of the left value.  But the left value may be greater than
-      // the right value.
-      double currentLeftLongitude = leftLongitude;
-      double currentRightLongitude = rightLongitude;
-      if (currentRightLongitude < currentLeftLongitude)
-        currentRightLongitude += 2.0 * Math.PI;
-      // We have a range to look at that's going in the right way.
-      // Now, do the same trick with the computed longitude.
-      if (longitude < currentLeftLongitude)
-        longitude += 2.0 * Math.PI;
-
-      if (longitude < currentLeftLongitude || longitude > currentRightLongitude) {
-        // Outside of current bounds.  Consider carefully how we'll expand.
-        double leftExtensionAmt;
-        double rightExtensionAmt;
-        if (longitude < currentLeftLongitude) {
-          leftExtensionAmt = currentLeftLongitude - longitude;
-        } else {
-          leftExtensionAmt = currentLeftLongitude + 2.0 * Math.PI - longitude;
-        }
-        if (longitude > currentRightLongitude) {
-          rightExtensionAmt = longitude - currentRightLongitude;
-        } else {
-          rightExtensionAmt = longitude + 2.0 * Math.PI - currentRightLongitude;
-        }
-        if (leftExtensionAmt < rightExtensionAmt) {
-          currentLeftLongitude = leftLongitude - leftExtensionAmt;
-          while (currentLeftLongitude <= -Math.PI) {
-            currentLeftLongitude += 2.0 * Math.PI;
-          }
-          leftLongitude = currentLeftLongitude;
-        } else {
-          currentRightLongitude = rightLongitude + rightExtensionAmt;
-          while (currentRightLongitude > Math.PI) {
-            currentRightLongitude -= 2.0 * Math.PI;
-          }
-          rightLongitude = currentRightLongitude;
-        }
-      }
-    }
-    double testRightLongitude = rightLongitude;
-    if (testRightLongitude < leftLongitude)
-      testRightLongitude += Math.PI * 2.0;
-    if (testRightLongitude - leftLongitude >= Math.PI) {
-      noLongitudeBound = true;
-      leftLongitude = null;
-      rightLongitude = null;
-    }
-  }
-
-}