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 & 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 & 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;
- }
- }
-
-}