You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by no...@apache.org on 2016/03/09 17:00:27 UTC
[16/50] [abbrv] lucene-solr git commit: LUCENE-7056: Geo3D package
re-org
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/f7f81c32/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/f7f81c32/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/f7f81c32/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/f7f81c32/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/f7f81c32/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/f7f81c32/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/f7f81c32/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/f7f81c32/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/f7f81c32/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/f7f81c32/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/f7f81c32/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/f7f81c32/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/f7f81c32/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/f7f81c32/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/f7f81c32/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/f7f81c32/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/f7f81c32/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/f7f81c32/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/f7f81c32/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/f7f81c32/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 + ")}";
+ }
+}