diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index 62a638f2bed..fe814481543 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -155,6 +155,9 @@ Other it, to eventually handle degenerate cases (Karl Wright via Mike McCandless) +* LUCENE-6800: Use XYZSolidFactory to create XYZSolids (Karl Wright + via Mike McCandless) + Build * LUCENE-6732: Improve checker for invalid source patterns to also diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/BaseXYZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/BaseXYZSolid.java index e7b46e9639d..3ac415eaf3d 100644 --- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/BaseXYZSolid.java +++ b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/BaseXYZSolid.java @@ -22,7 +22,7 @@ package org.apache.lucene.geo3d; * * @lucene.internal */ -public abstract class BaseXYZSolid extends BasePlanetObject implements GeoArea { +public abstract class BaseXYZSolid extends BasePlanetObject implements XYZSolid { /** Unit vector in x */ protected static final Vector xUnitVector = new Vector(1.0, 0.0, 0.0); diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoAreaFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoAreaFactory.java index 7fc4e60bc8a..c5a0f96ef6c 100755 --- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoAreaFactory.java +++ b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/GeoAreaFactory.java @@ -50,32 +50,7 @@ public class GeoAreaFactory { * @param maxZ is the max Z boundary */ public static GeoArea makeGeoArea(final PlanetModel planetModel, final double minX, final double maxX, final double minY, final double maxY, final double minZ, final double maxZ) { - if (Math.abs(maxX - minX) < Vector.MINIMUM_RESOLUTION) { - if (Math.abs(maxY - minY) < Vector.MINIMUM_RESOLUTION) { - if (Math.abs(maxZ - minZ) < Vector.MINIMUM_RESOLUTION) { - return new dXdYdZSolid(planetModel, (minX+maxX) * 0.5, (minY+maxY) * 0.5, minZ); - } else { - return new dXdYZSolid(planetModel, (minX+maxX) * 0.5, (minY+maxY) * 0.5, minZ, maxZ); - } - } else { - if (Math.abs(maxZ - minZ) < Vector.MINIMUM_RESOLUTION) { - return new dXYdZSolid(planetModel, (minX+maxX) * 0.5, minY, maxY, (minZ+maxZ) * 0.5); - } else { - return new dXYZSolid(planetModel, (minX+maxX) * 0.5, minY, maxY, minZ, maxZ); - } - } - } - if (Math.abs(maxY - minY) < Vector.MINIMUM_RESOLUTION) { - if (Math.abs(maxZ - minZ) < Vector.MINIMUM_RESOLUTION) { - return new XdYdZSolid(planetModel, minX, maxX, (minY+maxY) * 0.5, (minZ+maxZ) * 0.5); - } else { - return new XdYZSolid(planetModel, minX, maxX, (minY+maxY) * 0.5, minZ, maxZ); - } - } - if (Math.abs(maxZ - minZ) < Vector.MINIMUM_RESOLUTION) { - return new XYdZSolid(planetModel, minX, maxX, minY, maxY, (minZ+maxZ) * 0.5); - } - return new XYZSolid(planetModel, minX, maxX, minY, maxY, minZ, maxZ); + return XYZSolidFactory.makeXYZSolid(planetModel, minX, maxX, minY, maxY, minZ, maxZ); } } diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/StandardXYZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/StandardXYZSolid.java new file mode 100644 index 00000000000..5b7b69a853a --- /dev/null +++ b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/StandardXYZSolid.java @@ -0,0 +1,418 @@ +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 StandardXYZSolid extends BaseXYZSolid { + + /** Whole world? */ + protected final boolean isWholeWorld; + /** Min-X plane */ + protected final SidedPlane minXPlane; + /** Max-X plane */ + protected final SidedPlane maxXPlane; + /** Min-Y plane */ + protected final SidedPlane minYPlane; + /** Max-Y plane */ + protected final SidedPlane maxYPlane; + /** Min-Z plane */ + protected final SidedPlane minZPlane; + /** Max-Z plane */ + protected final SidedPlane maxZPlane; + + /** These are the edge points of the shape, which are defined to be at least one point on + * each surface area boundary. In the case of a solid, this includes points which represent + * the intersection of XYZ bounding planes and the planet, as well as points representing + * the intersection of single bounding planes with the planet itself. + */ + protected final GeoPoint[] edgePoints; + + /** Notable points for minXPlane */ + protected final GeoPoint[] notableMinXPoints; + /** Notable points for maxXPlane */ + protected final GeoPoint[] notableMaxXPoints; + /** Notable points for minYPlane */ + protected final GeoPoint[] notableMinYPoints; + /** Notable points for maxYPlane */ + protected final GeoPoint[] notableMaxYPoints; + /** Notable points for minZPlane */ + protected final GeoPoint[] notableMinZPoints; + /** Notable points for maxZPlane */ + protected final GeoPoint[] notableMaxZPoints; + + /** + * Sole constructor + * + *@param planetModel is the planet model. + *@param minX is the minimum X value. + *@param maxX is the maximum X value. + *@param minY is the minimum Y value. + *@param maxY is the maximum Y value. + *@param minZ is the minimum Z value. + *@param maxZ is the maximum Z value. + */ + public StandardXYZSolid(final PlanetModel planetModel, + final double minX, + final double maxX, + final double minY, + final double maxY, + final double minZ, + final double maxZ) { + super(planetModel); + // Argument checking + if (maxX - minX < Vector.MINIMUM_RESOLUTION) + throw new IllegalArgumentException("X values in wrong order or identical"); + if (maxY - minY < Vector.MINIMUM_RESOLUTION) + throw new IllegalArgumentException("Y values in wrong order or identical"); + if (maxZ - minZ < Vector.MINIMUM_RESOLUTION) + throw new IllegalArgumentException("Z values in wrong order or identical"); + + final double worldMinX = planetModel.getMinimumXValue(); + final double worldMaxX = planetModel.getMaximumXValue(); + final double worldMinY = planetModel.getMinimumYValue(); + final double worldMaxY = planetModel.getMaximumYValue(); + final double worldMinZ = planetModel.getMinimumZValue(); + final double worldMaxZ = planetModel.getMaximumZValue(); + + // We must distinguish between the case where the solid represents the entire world, + // and when the solid has no overlap with any part of the surface. In both cases, + // there will be no edgepoints. + isWholeWorld = + (minX - worldMinX < -Vector.MINIMUM_RESOLUTION) && + (maxX - worldMaxX > Vector.MINIMUM_RESOLUTION) && + (minY - worldMinY < -Vector.MINIMUM_RESOLUTION) && + (maxY - worldMaxY > Vector.MINIMUM_RESOLUTION) && + (minZ - worldMinZ < -Vector.MINIMUM_RESOLUTION) && + (maxZ - worldMaxZ > Vector.MINIMUM_RESOLUTION); + + if (isWholeWorld) { + minXPlane = null; + maxXPlane = null; + minYPlane = null; + maxYPlane = null; + minZPlane = null; + maxZPlane = null; + notableMinXPoints = null; + notableMaxXPoints = null; + notableMinYPoints = null; + notableMaxYPoints = null; + notableMinZPoints = null; + notableMaxZPoints = null; + edgePoints = null; + } else { + // Construct the planes + minXPlane = new SidedPlane(maxX,0.0,0.0,xUnitVector,-minX); + maxXPlane = new SidedPlane(minX,0.0,0.0,xUnitVector,-maxX); + minYPlane = new SidedPlane(0.0,maxY,0.0,yUnitVector,-minY); + maxYPlane = new SidedPlane(0.0,minY,0.0,yUnitVector,-maxY); + minZPlane = new SidedPlane(0.0,0.0,maxZ,zUnitVector,-minZ); + maxZPlane = new SidedPlane(0.0,0.0,minZ,zUnitVector,-maxZ); + + // We need at least one point on the planet surface for each manifestation of the shape. + // There can be up to 2 (on opposite sides of the world). But we have to go through + // 12 combinations of adjacent planes in order to find out if any have 2 intersection solution. + // Typically, this requires 12 square root operations. + final GeoPoint[] minXminY = minXPlane.findIntersections(planetModel,minYPlane,maxXPlane,maxYPlane,minZPlane,maxZPlane); + final GeoPoint[] minXmaxY = minXPlane.findIntersections(planetModel,maxYPlane,maxXPlane,minYPlane,minZPlane,maxZPlane); + final GeoPoint[] minXminZ = minXPlane.findIntersections(planetModel,minZPlane,maxXPlane,maxZPlane,minYPlane,maxYPlane); + final GeoPoint[] minXmaxZ = minXPlane.findIntersections(planetModel,maxZPlane,maxXPlane,minZPlane,minYPlane,maxYPlane); + + final GeoPoint[] maxXminY = maxXPlane.findIntersections(planetModel,minYPlane,minXPlane,maxYPlane,minZPlane,maxZPlane); + final GeoPoint[] maxXmaxY = maxXPlane.findIntersections(planetModel,maxYPlane,minXPlane,minYPlane,minZPlane,maxZPlane); + final GeoPoint[] maxXminZ = maxXPlane.findIntersections(planetModel,minZPlane,minXPlane,maxZPlane,minYPlane,maxYPlane); + final GeoPoint[] maxXmaxZ = maxXPlane.findIntersections(planetModel,maxZPlane,minXPlane,minZPlane,minYPlane,maxYPlane); + + final GeoPoint[] minYminZ = minYPlane.findIntersections(planetModel,minZPlane,maxYPlane,maxZPlane,minXPlane,maxXPlane); + final GeoPoint[] minYmaxZ = minYPlane.findIntersections(planetModel,maxZPlane,maxYPlane,minZPlane,minXPlane,maxXPlane); + final GeoPoint[] maxYminZ = maxYPlane.findIntersections(planetModel,minZPlane,minYPlane,maxZPlane,minXPlane,maxXPlane); + final GeoPoint[] maxYmaxZ = maxYPlane.findIntersections(planetModel,maxZPlane,minYPlane,minZPlane,minXPlane,maxXPlane); + + notableMinXPoints = glueTogether(minXminY, minXmaxY, minXminZ, minXmaxZ); + notableMaxXPoints = glueTogether(maxXminY, maxXmaxY, maxXminZ, maxXmaxZ); + notableMinYPoints = glueTogether(minXminY, maxXminY, minYminZ, minYmaxZ); + notableMaxYPoints = glueTogether(minXmaxY, maxXmaxY, maxYminZ, maxYmaxZ); + notableMinZPoints = glueTogether(minXminZ, maxXminZ, minYminZ, maxYminZ); + notableMaxZPoints = glueTogether(minXmaxZ, maxXmaxZ, minYmaxZ, maxYmaxZ); + + // Now, compute the edge points. + // This is the trickiest part of setting up an XYZSolid. We've computed intersections already, so + // we'll start there. + // There can be a number of shapes, each of which needs an edgepoint. Each side by itself might contribute + // an edgepoint, for instance, if the plane describing that side intercepts the planet in such a way that the ellipse + // of interception does not meet any other planes. Plane intersections can each contribute 0, 1, or 2 edgepoints. + // + // All of this makes for a lot of potential edgepoints, but I believe these can be pruned back with careful analysis. + // I haven't yet done that analysis, however, so I will treat them all as individual edgepoints. + + // The cases we are looking for are when the four corner points for any given + // plane are all outside of the world, AND that plane intersects the world. + // There are eight corner points all told; we must evaluate these WRT the planet surface. + final boolean minXminYminZ = planetModel.pointOutside(minX, minY, minZ); + final boolean minXminYmaxZ = planetModel.pointOutside(minX, minY, maxZ); + final boolean minXmaxYminZ = planetModel.pointOutside(minX, maxY, minZ); + final boolean minXmaxYmaxZ = planetModel.pointOutside(minX, maxY, maxZ); + final boolean maxXminYminZ = planetModel.pointOutside(maxX, minY, minZ); + final boolean maxXminYmaxZ = planetModel.pointOutside(maxX, minY, maxZ); + final boolean maxXmaxYminZ = planetModel.pointOutside(maxX, maxY, minZ); + final boolean maxXmaxYmaxZ = planetModel.pointOutside(maxX, maxY, maxZ); + + // Look at single-plane/world intersections. + // We detect these by looking at the world model and noting its x, y, and z bounds. + + final GeoPoint[] minXEdges; + if (minX - worldMinX >= -Vector.MINIMUM_RESOLUTION && minX - worldMaxX <= Vector.MINIMUM_RESOLUTION && + minY < 0.0 && maxY > 0.0 && minZ < 0.0 && maxZ > 0.0 && + minXminYminZ && minXminYmaxZ && minXmaxYminZ && minXmaxYmaxZ) { + // Find any point on the minX plane that intersects the world + // First construct a perpendicular plane that will allow us to find a sample point. + // This plane is vertical and goes through the points (0,0,0) and (1,0,0) + // Then use it to compute a sample point. + final GeoPoint intPoint = minXPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane); + if (intPoint != null) { + minXEdges = new GeoPoint[]{intPoint}; + } else { + // No intersection found? + minXEdges = EMPTY_POINTS; + } + } else { + minXEdges = EMPTY_POINTS; + } + + final GeoPoint[] maxXEdges; + if (maxX - worldMinX >= -Vector.MINIMUM_RESOLUTION && maxX - worldMaxX <= Vector.MINIMUM_RESOLUTION && + minY < 0.0 && maxY > 0.0 && minZ < 0.0 && maxZ > 0.0 && + maxXminYminZ && maxXminYmaxZ && maxXmaxYminZ && maxXmaxYmaxZ) { + // Find any point on the maxX plane that intersects the world + // First construct a perpendicular plane that will allow us to find a sample point. + // This plane is vertical and goes through the points (0,0,0) and (1,0,0) + // Then use it to compute a sample point. + final GeoPoint intPoint = maxXPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane); + if (intPoint != null) { + maxXEdges = new GeoPoint[]{intPoint}; + } else { + maxXEdges = EMPTY_POINTS; + } + } else { + maxXEdges = EMPTY_POINTS; + } + + final GeoPoint[] minYEdges; + if (minY - worldMinY >= -Vector.MINIMUM_RESOLUTION && minY - worldMaxY <= Vector.MINIMUM_RESOLUTION && + minX < 0.0 && maxX > 0.0 && minZ < 0.0 && maxZ > 0.0 && + minXminYminZ && minXminYmaxZ && maxXminYminZ && maxXminYmaxZ) { + // Find any point on the minY plane that intersects the world + // First construct a perpendicular plane that will allow us to find a sample point. + // This plane is vertical and goes through the points (0,0,0) and (0,1,0) + // Then use it to compute a sample point. + final GeoPoint intPoint = minYPlane.getSampleIntersectionPoint(planetModel, yVerticalPlane); + if (intPoint != null) { + minYEdges = new GeoPoint[]{intPoint}; + } else { + minYEdges = EMPTY_POINTS; + } + } else { + minYEdges = EMPTY_POINTS; + } + + final GeoPoint[] maxYEdges; + if (maxY - worldMinY >= -Vector.MINIMUM_RESOLUTION && maxY - worldMaxY <= Vector.MINIMUM_RESOLUTION && + minX < 0.0 && maxX > 0.0 && minZ < 0.0 && maxZ > 0.0 && + minXmaxYminZ && minXmaxYmaxZ && maxXmaxYminZ && maxXmaxYmaxZ) { + // Find any point on the maxY plane that intersects the world + // First construct a perpendicular plane that will allow us to find a sample point. + // This plane is vertical and goes through the points (0,0,0) and (0,1,0) + // Then use it to compute a sample point. + final GeoPoint intPoint = maxYPlane.getSampleIntersectionPoint(planetModel, yVerticalPlane); + if (intPoint != null) { + maxYEdges = new GeoPoint[]{intPoint}; + } else { + maxYEdges = EMPTY_POINTS; + } + } else { + maxYEdges = EMPTY_POINTS; + } + + final GeoPoint[] minZEdges; + if (minZ - worldMinZ >= -Vector.MINIMUM_RESOLUTION && minZ - worldMaxZ <= Vector.MINIMUM_RESOLUTION && + minX < 0.0 && maxX > 0.0 && minY < 0.0 && maxY > 0.0 && + minXminYminZ && minXmaxYminZ && maxXminYminZ && maxXmaxYminZ) { + // Find any point on the minZ plane that intersects the world + // First construct a perpendicular plane that will allow us to find a sample point. + // This plane is vertical and goes through the points (0,0,0) and (1,0,0) + // Then use it to compute a sample point. + final GeoPoint intPoint = minZPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane); + if (intPoint != null) { + minZEdges = new GeoPoint[]{intPoint}; + } else { + minZEdges = EMPTY_POINTS; + } + } else { + minZEdges = EMPTY_POINTS; + } + + final GeoPoint[] maxZEdges; + if (maxZ - worldMinZ >= -Vector.MINIMUM_RESOLUTION && maxZ - worldMaxZ <= Vector.MINIMUM_RESOLUTION && + minX < 0.0 && maxX > 0.0 && minY < 0.0 && maxY > 0.0 && + minXminYmaxZ && minXmaxYmaxZ && maxXminYmaxZ && maxXmaxYmaxZ) { + // Find any point on the maxZ plane that intersects the world + // First construct a perpendicular plane that will allow us to find a sample point. + // This plane is vertical and goes through the points (0,0,0) and (1,0,0) (that is, its orientation doesn't matter) + // Then use it to compute a sample point. + final GeoPoint intPoint = maxZPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane); + if (intPoint != null) { + maxZEdges = new GeoPoint[]{intPoint}; + } else { + maxZEdges = EMPTY_POINTS; + } + } else { + maxZEdges = EMPTY_POINTS; + } + + // Glue everything together. This is not a minimal set of edgepoints, as of now, but it does completely describe all shapes on the + // planet. + this.edgePoints = glueTogether(minXminY, minXmaxY, minXminZ, minXmaxZ, + maxXminY, maxXmaxY, maxXminZ, maxXmaxZ, + minYminZ, minYmaxZ, maxYminZ, maxYmaxZ, + minXEdges, maxXEdges, minYEdges, maxYEdges, minZEdges, maxZEdges); + } + } + + @Override + protected GeoPoint[] getEdgePoints() { + return edgePoints; + } + + @Override + public boolean isWithin(final double x, final double y, final double z) { + if (isWholeWorld) { + return true; + } + return minXPlane.isWithin(x, y, z) && + maxXPlane.isWithin(x, y, z) && + minYPlane.isWithin(x, y, z) && + maxYPlane.isWithin(x, y, z) && + minZPlane.isWithin(x, y, z) && + maxZPlane.isWithin(x, y, z); + } + + @Override + public int getRelationship(final GeoShape path) { + if (isWholeWorld) { + if (path.getEdgePoints().length > 0) + return WITHIN; + return OVERLAPS; + } + + /* + for (GeoPoint p : getEdgePoints()) { + System.err.println(" Edge point "+p+" path.isWithin()? "+path.isWithin(p)); + } + + for (GeoPoint p : path.getEdgePoints()) { + System.err.println(" path edge point "+p+" isWithin()? "+isWithin(p)+" minx="+minXPlane.evaluate(p)+" maxx="+maxXPlane.evaluate(p)+" miny="+minYPlane.evaluate(p)+" maxy="+maxYPlane.evaluate(p)+" minz="+minZPlane.evaluate(p)+" maxz="+maxZPlane.evaluate(p)); + } + */ + + //System.err.println(this+" getrelationship with "+path); + final int insideRectangle = isShapeInsideArea(path); + if (insideRectangle == SOME_INSIDE) { + //System.err.println(" some shape points inside area"); + return OVERLAPS; + } + + // Figure out if the entire XYZArea is contained by the shape. + final int insideShape = isAreaInsideShape(path); + if (insideShape == SOME_INSIDE) { + //System.err.println(" some area points inside shape"); + return OVERLAPS; + } + + if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) { + //System.err.println(" inside of each other"); + return OVERLAPS; + } + + if (path.intersects(minXPlane, notableMinXPoints, maxXPlane, minYPlane, maxYPlane, minZPlane, maxZPlane) || + path.intersects(maxXPlane, notableMaxXPoints, minXPlane, minYPlane, maxYPlane, minZPlane, maxZPlane) || + path.intersects(minYPlane, notableMinYPoints, maxYPlane, minXPlane, maxXPlane, minZPlane, maxZPlane) || + path.intersects(maxYPlane, notableMaxYPoints, minYPlane, minXPlane, maxXPlane, minZPlane, maxZPlane) || + path.intersects(minZPlane, notableMinZPoints, maxZPlane, minXPlane, maxXPlane, minYPlane, maxYPlane) || + path.intersects(maxZPlane, notableMaxZPoints, minZPlane, minXPlane, maxXPlane, minYPlane, maxYPlane)) { + //System.err.println(" edges intersect"); + return OVERLAPS; + } + + if (insideRectangle == ALL_INSIDE) { + //System.err.println(" all shape points inside area"); + return WITHIN; + } + + if (insideShape == ALL_INSIDE) { + //System.err.println(" all area points inside shape"); + return CONTAINS; + } + //System.err.println(" disjoint"); + return DISJOINT; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof StandardXYZSolid)) + return false; + StandardXYZSolid other = (StandardXYZSolid) o; + if (!super.equals(other) || + other.isWholeWorld != isWholeWorld) { + return false; + } + if (!isWholeWorld) { + return other.minXPlane.equals(minXPlane) && + other.maxXPlane.equals(maxXPlane) && + other.minYPlane.equals(minYPlane) && + other.maxYPlane.equals(maxYPlane) && + other.minZPlane.equals(minZPlane) && + other.maxZPlane.equals(maxZPlane); + } + return true; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (isWholeWorld?1:0); + if (!isWholeWorld) { + result = 31 * result + minXPlane.hashCode(); + result = 31 * result + maxXPlane.hashCode(); + result = 31 * result + minYPlane.hashCode(); + result = 31 * result + maxYPlane.hashCode(); + result = 31 * result + minZPlane.hashCode(); + result = 31 * result + maxZPlane.hashCode(); + } + return result; + } + + @Override + public String toString() { + return "StandardXYZSolid: {planetmodel="+planetModel+", isWholeWorld="+isWholeWorld+", minXplane="+minXPlane+", maxXplane="+maxXPlane+", minYplane="+minYPlane+", maxYplane="+maxYPlane+", minZplane="+minZPlane+", maxZplane="+maxZPlane+"}"; + } + +} + diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolid.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolid.java index 8703e444653..5fe72eb8ae1 100644 --- a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolid.java +++ b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolid.java @@ -18,401 +18,10 @@ package org.apache.lucene.geo3d; */ /** - * 3D rectangle, bounded on six sides by X,Y,Z limits + * Interface for a family of 3D rectangles, bounded on six sides by X,Y,Z limits * * @lucene.internal */ -public class XYZSolid extends BaseXYZSolid { - - /** Whole world? */ - protected final boolean isWholeWorld; - /** Min-X plane */ - protected final SidedPlane minXPlane; - /** Max-X plane */ - protected final SidedPlane maxXPlane; - /** Min-Y plane */ - protected final SidedPlane minYPlane; - /** Max-Y plane */ - protected final SidedPlane maxYPlane; - /** Min-Z plane */ - protected final SidedPlane minZPlane; - /** Max-Z plane */ - protected final SidedPlane maxZPlane; - - /** These are the edge points of the shape, which are defined to be at least one point on - * each surface area boundary. In the case of a solid, this includes points which represent - * the intersection of XYZ bounding planes and the planet, as well as points representing - * the intersection of single bounding planes with the planet itself. - */ - protected final GeoPoint[] edgePoints; - - /** Notable points for minXPlane */ - protected final GeoPoint[] notableMinXPoints; - /** Notable points for maxXPlane */ - protected final GeoPoint[] notableMaxXPoints; - /** Notable points for minYPlane */ - protected final GeoPoint[] notableMinYPoints; - /** Notable points for maxYPlane */ - protected final GeoPoint[] notableMaxYPoints; - /** Notable points for minZPlane */ - protected final GeoPoint[] notableMinZPoints; - /** Notable points for maxZPlane */ - protected final GeoPoint[] notableMaxZPoints; - - /** - * Sole constructor - * - *@param planetModel is the planet model. - *@param minX is the minimum X value. - *@param maxX is the maximum X value. - *@param minY is the minimum Y value. - *@param maxY is the maximum Y value. - *@param minZ is the minimum Z value. - *@param maxZ is the maximum Z value. - */ - public 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. - // There can be a number of shapes, each of which needs an edgepoint. Each side by itself might contribute - // an edgepoint, for instance, if the plane describing that side intercepts the planet in such a way that the ellipse - // of interception does not meet any other planes. Plane intersections can each contribute 0, 1, or 2 edgepoints. - // - // All of this makes for a lot of potential edgepoints, but I believe these can be pruned back with careful analysis. - // I haven't yet done that analysis, however, so I will treat them all as individual edgepoints. - - // The cases we are looking for are when the four corner points for any given - // plane are all outside of the world, AND that plane intersects the world. - // There are eight corner points all told; we must evaluate these WRT the planet surface. - final boolean minXminYminZ = planetModel.pointOutside(minX, minY, minZ); - final boolean minXminYmaxZ = planetModel.pointOutside(minX, minY, maxZ); - final boolean minXmaxYminZ = planetModel.pointOutside(minX, maxY, minZ); - final boolean minXmaxYmaxZ = planetModel.pointOutside(minX, maxY, maxZ); - final boolean maxXminYminZ = planetModel.pointOutside(maxX, minY, minZ); - final boolean maxXminYmaxZ = planetModel.pointOutside(maxX, minY, maxZ); - final boolean maxXmaxYminZ = planetModel.pointOutside(maxX, maxY, minZ); - final boolean maxXmaxYmaxZ = planetModel.pointOutside(maxX, maxY, maxZ); - - // Look at single-plane/world intersections. - // We detect these by looking at the world model and noting its x, y, and z bounds. - - final GeoPoint[] minXEdges; - if (minX - worldMinX >= -Vector.MINIMUM_RESOLUTION && minX - worldMaxX <= Vector.MINIMUM_RESOLUTION && - minY < 0.0 && maxY > 0.0 && minZ < 0.0 && maxZ > 0.0 && - minXminYminZ && minXminYmaxZ && minXmaxYminZ && minXmaxYmaxZ) { - // Find any point on the minX plane that intersects the world - // First construct a perpendicular plane that will allow us to find a sample point. - // This plane is vertical and goes through the points (0,0,0) and (1,0,0) - // Then use it to compute a sample point. - final GeoPoint intPoint = minXPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane); - if (intPoint != null) { - minXEdges = new GeoPoint[]{intPoint}; - } else { - // No intersection found? - minXEdges = EMPTY_POINTS; - } - } else { - minXEdges = EMPTY_POINTS; - } - - final GeoPoint[] maxXEdges; - if (maxX - worldMinX >= -Vector.MINIMUM_RESOLUTION && maxX - worldMaxX <= Vector.MINIMUM_RESOLUTION && - minY < 0.0 && maxY > 0.0 && minZ < 0.0 && maxZ > 0.0 && - maxXminYminZ && maxXminYmaxZ && maxXmaxYminZ && maxXmaxYmaxZ) { - // Find any point on the maxX plane that intersects the world - // First construct a perpendicular plane that will allow us to find a sample point. - // This plane is vertical and goes through the points (0,0,0) and (1,0,0) - // Then use it to compute a sample point. - final GeoPoint intPoint = maxXPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane); - if (intPoint != null) { - maxXEdges = new GeoPoint[]{intPoint}; - } else { - maxXEdges = EMPTY_POINTS; - } - } else { - maxXEdges = EMPTY_POINTS; - } - - final GeoPoint[] minYEdges; - if (minY - worldMinY >= -Vector.MINIMUM_RESOLUTION && minY - worldMaxY <= Vector.MINIMUM_RESOLUTION && - minX < 0.0 && maxX > 0.0 && minZ < 0.0 && maxZ > 0.0 && - minXminYminZ && minXminYmaxZ && maxXminYminZ && maxXminYmaxZ) { - // Find any point on the minY plane that intersects the world - // First construct a perpendicular plane that will allow us to find a sample point. - // This plane is vertical and goes through the points (0,0,0) and (0,1,0) - // Then use it to compute a sample point. - final GeoPoint intPoint = minYPlane.getSampleIntersectionPoint(planetModel, yVerticalPlane); - if (intPoint != null) { - minYEdges = new GeoPoint[]{intPoint}; - } else { - minYEdges = EMPTY_POINTS; - } - } else { - minYEdges = EMPTY_POINTS; - } - - final GeoPoint[] maxYEdges; - if (maxY - worldMinY >= -Vector.MINIMUM_RESOLUTION && maxY - worldMaxY <= Vector.MINIMUM_RESOLUTION && - minX < 0.0 && maxX > 0.0 && minZ < 0.0 && maxZ > 0.0 && - minXmaxYminZ && minXmaxYmaxZ && maxXmaxYminZ && maxXmaxYmaxZ) { - // Find any point on the maxY plane that intersects the world - // First construct a perpendicular plane that will allow us to find a sample point. - // This plane is vertical and goes through the points (0,0,0) and (0,1,0) - // Then use it to compute a sample point. - final GeoPoint intPoint = maxYPlane.getSampleIntersectionPoint(planetModel, yVerticalPlane); - if (intPoint != null) { - maxYEdges = new GeoPoint[]{intPoint}; - } else { - maxYEdges = EMPTY_POINTS; - } - } else { - maxYEdges = EMPTY_POINTS; - } - - final GeoPoint[] minZEdges; - if (minZ - worldMinZ >= -Vector.MINIMUM_RESOLUTION && minZ - worldMaxZ <= Vector.MINIMUM_RESOLUTION && - minX < 0.0 && maxX > 0.0 && minY < 0.0 && maxY > 0.0 && - minXminYminZ && minXmaxYminZ && maxXminYminZ && maxXmaxYminZ) { - // Find any point on the minZ plane that intersects the world - // First construct a perpendicular plane that will allow us to find a sample point. - // This plane is vertical and goes through the points (0,0,0) and (1,0,0) - // Then use it to compute a sample point. - final GeoPoint intPoint = minZPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane); - if (intPoint != null) { - minZEdges = new GeoPoint[]{intPoint}; - } else { - minZEdges = EMPTY_POINTS; - } - } else { - minZEdges = EMPTY_POINTS; - } - - final GeoPoint[] maxZEdges; - if (maxZ - worldMinZ >= -Vector.MINIMUM_RESOLUTION && maxZ - worldMaxZ <= Vector.MINIMUM_RESOLUTION && - minX < 0.0 && maxX > 0.0 && minY < 0.0 && maxY > 0.0 && - minXminYmaxZ && minXmaxYmaxZ && maxXminYmaxZ && maxXmaxYmaxZ) { - // Find any point on the maxZ plane that intersects the world - // First construct a perpendicular plane that will allow us to find a sample point. - // This plane is vertical and goes through the points (0,0,0) and (1,0,0) (that is, its orientation doesn't matter) - // Then use it to compute a sample point. - final GeoPoint intPoint = maxZPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane); - if (intPoint != null) { - maxZEdges = new GeoPoint[]{intPoint}; - } else { - maxZEdges = EMPTY_POINTS; - } - } else { - maxZEdges = EMPTY_POINTS; - } - - // Glue everything together. This is not a minimal set of edgepoints, as of now, but it does completely describe all shapes on the - // planet. - this.edgePoints = glueTogether(minXminY, minXmaxY, minXminZ, minXmaxZ, - maxXminY, maxXmaxY, maxXminZ, maxXmaxZ, - minYminZ, minYmaxZ, maxYminZ, maxYmaxZ, - minXEdges, maxXEdges, minYEdges, maxYEdges, minZEdges, maxZEdges); - } - } - - @Override - protected GeoPoint[] getEdgePoints() { - return edgePoints; - } - - @Override - public boolean isWithin(final double x, final double y, final double z) { - if (isWholeWorld) { - return true; - } - return minXPlane.isWithin(x, y, z) && - maxXPlane.isWithin(x, y, z) && - minYPlane.isWithin(x, y, z) && - maxYPlane.isWithin(x, y, z) && - minZPlane.isWithin(x, y, z) && - maxZPlane.isWithin(x, y, z); - } - - @Override - public int getRelationship(final GeoShape path) { - if (isWholeWorld) { - if (path.getEdgePoints().length > 0) - return WITHIN; - return OVERLAPS; - } - - /* - for (GeoPoint p : getEdgePoints()) { - System.err.println(" Edge point "+p+" path.isWithin()? "+path.isWithin(p)); - } - - for (GeoPoint p : path.getEdgePoints()) { - System.err.println(" path edge point "+p+" isWithin()? "+isWithin(p)+" minx="+minXPlane.evaluate(p)+" maxx="+maxXPlane.evaluate(p)+" miny="+minYPlane.evaluate(p)+" maxy="+maxYPlane.evaluate(p)+" minz="+minZPlane.evaluate(p)+" maxz="+maxZPlane.evaluate(p)); - } - */ - - //System.err.println(this+" getrelationship with "+path); - final int insideRectangle = isShapeInsideArea(path); - if (insideRectangle == SOME_INSIDE) { - //System.err.println(" some shape points inside area"); - return OVERLAPS; - } - - // Figure out if the entire XYZArea is contained by the shape. - final int insideShape = isAreaInsideShape(path); - if (insideShape == SOME_INSIDE) { - //System.err.println(" some area points inside shape"); - return OVERLAPS; - } - - if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) { - //System.err.println(" inside of each other"); - return OVERLAPS; - } - - if (path.intersects(minXPlane, notableMinXPoints, maxXPlane, minYPlane, maxYPlane, minZPlane, maxZPlane) || - path.intersects(maxXPlane, notableMaxXPoints, minXPlane, minYPlane, maxYPlane, minZPlane, maxZPlane) || - path.intersects(minYPlane, notableMinYPoints, maxYPlane, minXPlane, maxXPlane, minZPlane, maxZPlane) || - path.intersects(maxYPlane, notableMaxYPoints, minYPlane, minXPlane, maxXPlane, minZPlane, maxZPlane) || - path.intersects(minZPlane, notableMinZPoints, maxZPlane, minXPlane, maxXPlane, minYPlane, maxYPlane) || - path.intersects(maxZPlane, notableMaxZPoints, minZPlane, minXPlane, maxXPlane, minYPlane, maxYPlane)) { - //System.err.println(" edges intersect"); - return OVERLAPS; - } - - if (insideRectangle == ALL_INSIDE) { - //System.err.println(" all shape points inside area"); - return WITHIN; - } - - if (insideShape == ALL_INSIDE) { - //System.err.println(" all area points inside shape"); - return CONTAINS; - } - //System.err.println(" disjoint"); - return DISJOINT; - } - - @Override - public boolean equals(Object o) { - if (!(o instanceof 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(maxXPlane) && - other.minYPlane.equals(minYPlane) && - other.maxYPlane.equals(maxYPlane) && - other.minZPlane.equals(minZPlane) && - other.maxZPlane.equals(maxZPlane); - } - return true; - } - - @Override - public int hashCode() { - int result = super.hashCode(); - result = 31 * result + (isWholeWorld?1:0); - if (!isWholeWorld) { - result = 31 * result + minXPlane.hashCode(); - result = 31 * result + maxXPlane.hashCode(); - result = 31 * result + minYPlane.hashCode(); - result = 31 * result + maxYPlane.hashCode(); - result = 31 * result + minZPlane.hashCode(); - result = 31 * result + maxZPlane.hashCode(); - } - return result; - } - - @Override - public String toString() { - return "XYZSolid: {planetmodel="+planetModel+", isWholeWorld="+isWholeWorld+", minXplane="+minXPlane+", maxXplane="+maxXPlane+", minYplane="+minYPlane+", maxYplane="+maxYPlane+", minZplane="+minZPlane+", maxZplane="+maxZPlane+"}"; - } - +public interface XYZSolid extends GeoArea { } diff --git a/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolidFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolidFactory.java new file mode 100644 index 00000000000..b13a24f8160 --- /dev/null +++ b/lucene/spatial3d/src/java/org/apache/lucene/geo3d/XYZSolidFactory.java @@ -0,0 +1,68 @@ +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. + */ + +/** + * Factory for {@link org.apache.lucene.geo3d.XYZSolid}. + * + * @lucene.experimental + */ +public class XYZSolidFactory { + private XYZSolidFactory() { + } + + /** + * Create a XYZSolid of the right kind given (x,y,z) bounds. + * @param planetModel is the planet model + * @param minX is the min X boundary + * @param maxX is the max X boundary + * @param minY is the min Y boundary + * @param maxY is the max Y boundary + * @param minZ is the min Z boundary + * @param maxZ is the max Z boundary + */ + public static XYZSolid makeXYZSolid(final PlanetModel planetModel, final double minX, final double maxX, final double minY, final double maxY, final double minZ, final double maxZ) { + if (Math.abs(maxX - minX) < Vector.MINIMUM_RESOLUTION) { + if (Math.abs(maxY - minY) < Vector.MINIMUM_RESOLUTION) { + if (Math.abs(maxZ - minZ) < Vector.MINIMUM_RESOLUTION) { + return new dXdYdZSolid(planetModel, (minX+maxX) * 0.5, (minY+maxY) * 0.5, minZ); + } else { + return new dXdYZSolid(planetModel, (minX+maxX) * 0.5, (minY+maxY) * 0.5, minZ, maxZ); + } + } else { + if (Math.abs(maxZ - minZ) < Vector.MINIMUM_RESOLUTION) { + return new dXYdZSolid(planetModel, (minX+maxX) * 0.5, minY, maxY, (minZ+maxZ) * 0.5); + } else { + return new dXYZSolid(planetModel, (minX+maxX) * 0.5, minY, maxY, minZ, maxZ); + } + } + } + if (Math.abs(maxY - minY) < Vector.MINIMUM_RESOLUTION) { + if (Math.abs(maxZ - minZ) < Vector.MINIMUM_RESOLUTION) { + return new XdYdZSolid(planetModel, minX, maxX, (minY+maxY) * 0.5, (minZ+maxZ) * 0.5); + } else { + return new XdYZSolid(planetModel, minX, maxX, (minY+maxY) * 0.5, minZ, maxZ); + } + } + if (Math.abs(maxZ - minZ) < Vector.MINIMUM_RESOLUTION) { + return new XYdZSolid(planetModel, minX, maxX, minY, maxY, (minZ+maxZ) * 0.5); + } + return new StandardXYZSolid(planetModel, minX, maxX, minY, maxY, minZ, maxZ); + } + +} diff --git a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/XYZSolidTest.java b/lucene/spatial3d/src/test/org/apache/lucene/geo3d/XYZSolidTest.java index 5418812c3ae..4654f51ada9 100644 --- a/lucene/spatial3d/src/test/org/apache/lucene/geo3d/XYZSolidTest.java +++ b/lucene/spatial3d/src/test/org/apache/lucene/geo3d/XYZSolidTest.java @@ -27,7 +27,7 @@ public class XYZSolidTest extends LuceneTestCase { 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); + s = new StandardXYZSolid(PlanetModel.SPHERE, -2.0, 2.0, -2.0, 2.0, -2.0, 2.0); // Any shape, except whole world, should be within. shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1); assertEquals(GeoArea.WITHIN, s.getRelationship(shape)); @@ -37,7 +37,7 @@ public class XYZSolidTest extends LuceneTestCase { 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); + s = new StandardXYZSolid(PlanetModel.SPHERE, -2.0, 0.0, -2.0, 2.0, -2.0, 2.0); // Some things should be disjoint... shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1); assertEquals(GeoArea.DISJOINT, s.getRelationship(shape)); @@ -53,7 +53,7 @@ public class XYZSolidTest extends LuceneTestCase { 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); + s = new StandardXYZSolid(PlanetModel.SPHERE, -0.1, 0.1, -0.1, 0.1, -0.1, 0.1); // All shapes should be disjoint shape = new GeoStandardCircle(PlanetModel.SPHERE, 0.0, 0.0, 0.1); assertEquals(GeoArea.DISJOINT, s.getRelationship(shape));