You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by mi...@apache.org on 2015/08/11 22:33:00 UTC

svn commit: r1695369 - in /lucene/dev/branches/lucene6699/lucene/spatial3d/src: java/org/apache/lucene/geo3d/ test/org/apache/lucene/geo3d/

Author: mikemccand
Date: Tue Aug 11 20:33:00 2015
New Revision: 1695369

URL: http://svn.apache.org/r1695369
Log:
LUCENE-6699: Karl's patch to extend geo3d apis to 3d rectangles

Added:
    lucene/dev/branches/lucene6699/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolid.java   (with props)
    lucene/dev/branches/lucene6699/lucene/spatial3d/src/test/org/apache/lucene/geo3d/XYZSolidTest.java   (with props)
Modified:
    lucene/dev/branches/lucene6699/lucene/spatial3d/src/java/org/apache/lucene/geo3d/PlanetModel.java
    lucene/dev/branches/lucene6699/lucene/spatial3d/src/java/org/apache/lucene/geo3d/SidedPlane.java

Modified: lucene/dev/branches/lucene6699/lucene/spatial3d/src/java/org/apache/lucene/geo3d/PlanetModel.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6699/lucene/spatial3d/src/java/org/apache/lucene/geo3d/PlanetModel.java?rev=1695369&r1=1695368&r2=1695369&view=diff
==============================================================================
--- lucene/dev/branches/lucene6699/lucene/spatial3d/src/java/org/apache/lucene/geo3d/PlanetModel.java (original)
+++ lucene/dev/branches/lucene6699/lucene/spatial3d/src/java/org/apache/lucene/geo3d/PlanetModel.java Tue Aug 11 20:33:00 2015
@@ -97,6 +97,48 @@ public class PlanetModel {
     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;
+  }
+
   /** Compute surface distance between two points.
    * @param p1 is the first point.
    * @param p2 is the second point.

Modified: lucene/dev/branches/lucene6699/lucene/spatial3d/src/java/org/apache/lucene/geo3d/SidedPlane.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6699/lucene/spatial3d/src/java/org/apache/lucene/geo3d/SidedPlane.java?rev=1695369&r1=1695368&r2=1695369&view=diff
==============================================================================
--- lucene/dev/branches/lucene6699/lucene/spatial3d/src/java/org/apache/lucene/geo3d/SidedPlane.java (original)
+++ lucene/dev/branches/lucene6699/lucene/spatial3d/src/java/org/apache/lucene/geo3d/SidedPlane.java Tue Aug 11 20:33:00 2015
@@ -86,6 +86,20 @@ public class SidedPlane extends Plane im
     sigNum = Math.signum(evaluate(p));
   }
 
+  /**
+   * 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));
+  }
+
   /** Construct a sided plane from two points and a third normal vector.
    */
   public static SidedPlane constructNormalizedPerpendicularSidedPlane(final Vector insidePoint,

Added: lucene/dev/branches/lucene6699/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolid.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6699/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolid.java?rev=1695369&view=auto
==============================================================================
--- lucene/dev/branches/lucene6699/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolid.java (added)
+++ lucene/dev/branches/lucene6699/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolid.java Tue Aug 11 20:33:00 2015
@@ -0,0 +1,465 @@
+package org.apache.lucene.geo3d;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * 3D rectangle, bounded on six sides by X,Y,Z limits
+ *
+ * @lucene.internal
+ */
+public class XYZSolid extends BasePlanetObject implements GeoArea {
+
+  /** 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);
+  
+  /** 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;
+
+  /**
+   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
+   *@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 XYZSolid(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.  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.
+      GeoPoint[] edgePoints = findLargestSolution(minXminY,minXmaxY,minXminZ,minXmaxZ,
+        maxXminY,maxXmaxY,maxXminZ,maxXmaxZ,
+        minYminZ,minYmaxZ,maxYminZ,maxYmaxZ);
+      
+      if (edgePoints.length == 0) {
+        // 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.
+
+        if (minX - worldMinX >= -Vector.MINIMUM_RESOLUTION && minX - worldMaxX <= 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)) {
+          // 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.
+          edgePoints = new GeoPoint[]{minXPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane)};
+        } else if (maxX - worldMinX >= -Vector.MINIMUM_RESOLUTION && maxX - worldMaxX <= Vector.MINIMUM_RESOLUTION &&
+          (minX - worldMinX < -Vector.MINIMUM_RESOLUTION) &&
+          (minY - worldMinY < -Vector.MINIMUM_RESOLUTION) &&
+          (maxY - worldMaxY > Vector.MINIMUM_RESOLUTION) &&
+          (minZ - worldMinZ < -Vector.MINIMUM_RESOLUTION) &&
+          (maxZ - worldMaxZ > Vector.MINIMUM_RESOLUTION)) {
+          // 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.
+          edgePoints = new GeoPoint[]{maxXPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane)};
+        } else if (minY - worldMinY >= -Vector.MINIMUM_RESOLUTION && minY - worldMaxY <= Vector.MINIMUM_RESOLUTION &&
+          (maxY - worldMaxY > Vector.MINIMUM_RESOLUTION) &&
+          (minX - worldMinX < -Vector.MINIMUM_RESOLUTION) &&
+          (maxX - worldMaxX > Vector.MINIMUM_RESOLUTION) &&
+          (minZ - worldMinZ < -Vector.MINIMUM_RESOLUTION) &&
+          (maxZ - worldMaxZ > Vector.MINIMUM_RESOLUTION)) {
+          // 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.
+          edgePoints = new GeoPoint[]{minYPlane.getSampleIntersectionPoint(planetModel, yVerticalPlane)};
+        } else if (maxY - worldMinY >= -Vector.MINIMUM_RESOLUTION && maxY - worldMaxY <= Vector.MINIMUM_RESOLUTION &&
+          (minY - worldMinY < -Vector.MINIMUM_RESOLUTION) &&
+          (minX - worldMinX < -Vector.MINIMUM_RESOLUTION) &&
+          (maxX - worldMaxX > Vector.MINIMUM_RESOLUTION) &&
+          (minZ - worldMinZ < -Vector.MINIMUM_RESOLUTION) &&
+          (maxZ - worldMaxZ > Vector.MINIMUM_RESOLUTION)) {
+          // 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.
+          edgePoints = new GeoPoint[]{maxYPlane.getSampleIntersectionPoint(planetModel, yVerticalPlane)};
+        } else if (minZ - worldMinZ >= -Vector.MINIMUM_RESOLUTION && minZ - worldMaxZ <= Vector.MINIMUM_RESOLUTION &&
+          (maxZ - worldMaxZ > Vector.MINIMUM_RESOLUTION) &&
+          (minY - worldMinY < -Vector.MINIMUM_RESOLUTION) &&
+          (maxY - worldMaxY > Vector.MINIMUM_RESOLUTION) &&
+          (minX - worldMinX < -Vector.MINIMUM_RESOLUTION) &&
+          (maxX - worldMaxX > Vector.MINIMUM_RESOLUTION)) {
+          // 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.
+          edgePoints = new GeoPoint[]{minZPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane)};
+        } else if (maxZ - worldMinZ >= -Vector.MINIMUM_RESOLUTION && maxZ - worldMaxZ <= Vector.MINIMUM_RESOLUTION &&
+          (minZ - worldMinZ < -Vector.MINIMUM_RESOLUTION) &&
+          (minY - worldMinY < -Vector.MINIMUM_RESOLUTION) &&
+          (maxY - worldMaxY > Vector.MINIMUM_RESOLUTION) &&
+          (minX - worldMinX < -Vector.MINIMUM_RESOLUTION) &&
+          (maxX - worldMaxX > Vector.MINIMUM_RESOLUTION)) {
+          // 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.
+          edgePoints = new GeoPoint[]{maxZPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane)};
+        }
+      }
+
+      this.edgePoints = edgePoints;
+    }
+  }
+
+  /** 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;
+  }
+  
+  /** Find the longest set of point solutions.
+   * @param pointArrays is the array of point arrays.
+   * @return one of the longest sets.
+   */
+  protected static GeoPoint[] findLargestSolution(final GeoPoint[]... pointArrays) {
+    GeoPoint[] rval = null;
+    for (final GeoPoint[] pointArray : pointArrays) {
+      if (rval == null || rval.length < pointArray.length) {
+        rval = pointArray;
+      }
+    }
+    return rval;
+  }
+  
+  @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) {
+    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);
+  }
+
+  // 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) {
+    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;
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    if (isWholeWorld) {
+      if (path.getEdgePoints().length > 0)
+        return WITHIN;
+      return OVERLAPS;
+    }
+    
+    //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(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(" 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 XYZSolid))
+      return false;
+    XYZSolid other = (XYZSolid) o;
+    if (!super.equals(other) ||
+      other.isWholeWorld != isWholeWorld) {
+      return false;
+    }
+    if (!isWholeWorld) {
+      return other.minXPlane.equals(minXPlane) &&
+        other.maxXPlane.equals(maxYPlane) &&
+        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 "XYZSolid: {planetmodel="+planetModel+", isWholeWorld="+isWholeWorld+", minXplane="+minXPlane+", maxXplane="+maxXPlane+", minYplane="+minYPlane+", maxYplane="+maxYPlane+", minZplane="+minZPlane+", maxZplane="+maxZPlane+"}";
+  }
+  
+}
+  

Added: lucene/dev/branches/lucene6699/lucene/spatial3d/src/test/org/apache/lucene/geo3d/XYZSolidTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6699/lucene/spatial3d/src/test/org/apache/lucene/geo3d/XYZSolidTest.java?rev=1695369&view=auto
==============================================================================
--- lucene/dev/branches/lucene6699/lucene/spatial3d/src/test/org/apache/lucene/geo3d/XYZSolidTest.java (added)
+++ lucene/dev/branches/lucene6699/lucene/spatial3d/src/test/org/apache/lucene/geo3d/XYZSolidTest.java Tue Aug 11 20:33:00 2015
@@ -0,0 +1,71 @@
+package org.apache.lucene.geo3d;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class XYZSolidTest {
+
+
+  @Test
+  public void testRelationships() {
+    XYZSolid s;
+    GeoShape shape;
+    // Something bigger than the world
+    s = new XYZSolid(PlanetModel.SPHERE, -2.0, 2.0, -2.0, 2.0, -2.0, 2.0);
+    // Any shape, including world, should be within.
+    shape = new GeoCircle(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 XYZSolid(PlanetModel.SPHERE, -2.0, 0.0, -2.0, 2.0, -2.0, 2.0);
+    // Some things should be disjoint...
+    shape = new GeoCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1);
+    assertEquals(GeoArea.DISJOINT, s.getRelationship(shape));
+    // And, some things should be within... 
+    shape = new GeoCircle(PlanetModel.SPHERE, 0.0, Math.PI, 0.1);
+    assertEquals(GeoArea.WITHIN, s.getRelationship(shape));
+    // And, some things should overlap.
+    shape = new GeoCircle(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 XYZSolid(PlanetModel.SPHERE, -0.1, 0.1, -0.1, 0.1, -0.1, 0.1);
+    // All shapes should be disjoint
+    shape = new GeoCircle(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));
+    
+  }
+
+
+}