
org.apache.lucene.spatial3d.geom.XYZBounds Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of lucene-spatial3d Show documentation
Show all versions of lucene-spatial3d Show documentation
Lucene Spatial shapes implemented using 3D planar geometry
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.spatial3d.geom;
/**
* An object for accumulating XYZ bounds information.
*
* @lucene.experimental
*/
public class XYZBounds implements Bounds {
/**
* A 'fudge factor', which is added to maximums and subtracted from minimums, in order to
* compensate for potential error deltas. This would not be necessary except that our 'bounds' is
* defined as always equaling or exceeding the boundary of the shape, and we cannot guarantee that
* without making MINIMUM_RESOLUTION unacceptably large. Also, see LUCENE-7290 for a description
* of how geometry can magnify the bounds delta.
*/
private static final double FUDGE_FACTOR = Vector.MINIMUM_RESOLUTION * 1e3;
/** Minimum x */
private Double minX = null;
/** Maximum x */
private Double maxX = null;
/** Minimum y */
private Double minY = null;
/** Maximum y */
private Double maxY = null;
/** Minimum z */
private Double minZ = null;
/** Maximum z */
private Double maxZ = null;
/** Construct an empty bounds object */
public XYZBounds() {}
// Accessor methods
/**
* Return the minimum X value.
*
* @return minimum X value.
*/
public Double getMinimumX() {
return minX;
}
/**
* Return the maximum X value.
*
* @return maximum X value.
*/
public Double getMaximumX() {
return maxX;
}
/**
* Return the minimum Y value.
*
* @return minimum Y value.
*/
public Double getMinimumY() {
return minY;
}
/**
* Return the maximum Y value.
*
* @return maximum Y value.
*/
public Double getMaximumY() {
return maxY;
}
/**
* Return the minimum Z value.
*
* @return minimum Z value.
*/
public Double getMinimumZ() {
return minZ;
}
/**
* Return the maximum Z value.
*
* @return maximum Z value.
*/
public Double getMaximumZ() {
return maxZ;
}
/**
* Return true if minX is as small as the planet model allows.
*
* @return true if minX has reached its bound.
*/
public boolean isSmallestMinX(final PlanetModel planetModel) {
if (minX == null) {
return false;
}
return minX - planetModel.getMinimumXValue() < Vector.MINIMUM_RESOLUTION;
}
/**
* Return true if maxX is as large as the planet model allows.
*
* @return true if maxX has reached its bound.
*/
public boolean isLargestMaxX(final PlanetModel planetModel) {
if (maxX == null) {
return false;
}
return planetModel.getMaximumXValue() - maxX < Vector.MINIMUM_RESOLUTION;
}
/**
* Return true if minY is as small as the planet model allows.
*
* @return true if minY has reached its bound.
*/
public boolean isSmallestMinY(final PlanetModel planetModel) {
if (minY == null) {
return false;
}
return minY - planetModel.getMinimumYValue() < Vector.MINIMUM_RESOLUTION;
}
/**
* Return true if maxY is as large as the planet model allows.
*
* @return true if maxY has reached its bound.
*/
public boolean isLargestMaxY(final PlanetModel planetModel) {
if (maxY == null) {
return false;
}
return planetModel.getMaximumYValue() - maxY < Vector.MINIMUM_RESOLUTION;
}
/**
* Return true if minZ is as small as the planet model allows.
*
* @return true if minZ has reached its bound.
*/
public boolean isSmallestMinZ(final PlanetModel planetModel) {
if (minZ == null) {
return false;
}
return minZ - planetModel.getMinimumZValue() < Vector.MINIMUM_RESOLUTION;
}
/**
* Return true if maxZ is as large as the planet model allows.
*
* @return true if maxZ has reached its bound.
*/
public boolean isLargestMaxZ(final PlanetModel planetModel) {
if (maxZ == null) {
return false;
}
return planetModel.getMaximumZValue() - maxZ < Vector.MINIMUM_RESOLUTION;
}
// Modification methods
/**
* Check if another XYZBounds object overlaps this one.
*
* @param bounds is the other bounds object.
* @return true if there is overlap.
*/
public boolean overlaps(final XYZBounds bounds) {
// Overlap occurs when any one corner is inside the other bounds
// object, and visa versa
return isCornerInside(this, bounds) || isCornerInside(bounds, this);
}
private static boolean isCornerInside(final XYZBounds one, final XYZBounds other) {
if (one.minX == null
|| one.maxX == null
|| one.minY == null
|| one.maxY == null
|| one.minZ == null
|| one.maxZ == null) {
return false;
}
if (other.minX == null
|| other.maxX == null
|| other.minY == null
|| other.maxY == null
|| other.minZ == null
|| other.maxZ == null) {
return false;
}
return isPointInside(other, one.minX, one.minY, one.minZ)
|| isPointInside(other, one.maxX, one.minY, one.minZ)
|| isPointInside(other, one.minX, one.maxY, one.minZ)
|| isPointInside(other, one.maxX, one.maxY, one.minZ)
|| isPointInside(other, one.minX, one.minY, one.maxZ)
|| isPointInside(other, one.maxX, one.minY, one.maxZ)
|| isPointInside(other, one.minX, one.maxY, one.maxZ)
|| isPointInside(other, one.maxX, one.maxY, one.maxZ);
}
private static boolean isPointInside(
final XYZBounds other, final double x, final double y, final double z) {
return other.minX <= x
&& other.maxX >= x
&& other.minY <= y
&& other.maxY >= y
&& other.minZ <= z
&& other.maxZ >= z;
}
/**
* Add a fully-formed XYZBounds to the current one.
*
* @param bounds is the bounds object to modify
*/
public void addBounds(final XYZBounds bounds) {
if (bounds.maxX == null || maxX > bounds.maxX) {
bounds.maxX = maxX;
}
if (bounds.minX == null || minX < bounds.minX) {
bounds.minX = minX;
}
if (bounds.maxY == null || maxY > bounds.maxY) {
bounds.maxY = maxY;
}
if (bounds.minY == null || minY < bounds.minY) {
bounds.minY = minY;
}
if (bounds.maxZ == null || maxZ > bounds.maxZ) {
bounds.maxZ = maxZ;
}
if (bounds.minZ == null || minZ < bounds.minZ) {
bounds.minZ = minZ;
}
}
@Override
public Bounds addPlane(
final PlanetModel planetModel, final Plane plane, final Membership... bounds) {
plane.recordBounds(planetModel, this, bounds);
return this;
}
/**
* Add a horizontal plane to the bounds description. This method should EITHER use the supplied
* latitude, OR use the supplied plane, depending on what is most efficient.
*
* @param planetModel is the planet model.
* @param latitude is the latitude.
* @param horizontalPlane is the plane.
* @param bounds are the constraints on the plane.
* @return updated Bounds object.
*/
@Override
public Bounds addHorizontalPlane(
final PlanetModel planetModel,
final double latitude,
final Plane horizontalPlane,
final Membership... bounds) {
return addPlane(planetModel, horizontalPlane, bounds);
}
/**
* Add a vertical plane to the bounds description. This method should EITHER use the supplied
* longitude, OR use the supplied plane, depending on what is most efficient.
*
* @param planetModel is the planet model.
* @param longitude is the longitude.
* @param verticalPlane is the plane.
* @param bounds are the constraints on the plane.
* @return updated Bounds object.
*/
@Override
public Bounds addVerticalPlane(
final PlanetModel planetModel,
final double longitude,
final Plane verticalPlane,
final Membership... bounds) {
return addPlane(planetModel, verticalPlane, bounds);
}
@Override
public Bounds addXValue(final GeoPoint point) {
return addXValue(point.x);
}
/**
* Add a specific X value.
*
* @param x is the value to add.
* @return the bounds object.
*/
public Bounds addXValue(final double x) {
final double small = x - FUDGE_FACTOR;
if (minX == null || minX > small) {
minX = small;
}
final double large = x + FUDGE_FACTOR;
if (maxX == null || maxX < large) {
maxX = large;
}
return this;
}
@Override
public Bounds addYValue(final GeoPoint point) {
return addYValue(point.y);
}
/**
* Add a specific Y value.
*
* @param y is the value to add.
* @return the bounds object.
*/
public Bounds addYValue(final double y) {
final double small = y - FUDGE_FACTOR;
if (minY == null || minY > small) {
minY = small;
}
final double large = y + FUDGE_FACTOR;
if (maxY == null || maxY < large) {
maxY = large;
}
return this;
}
@Override
public Bounds addZValue(final GeoPoint point) {
return addZValue(point.z);
}
/**
* Add a specific Z value.
*
* @param z is the value to add.
* @return the bounds object.
*/
public Bounds addZValue(final double z) {
final double small = z - FUDGE_FACTOR;
if (minZ == null || minZ > small) {
minZ = small;
}
final double large = z + FUDGE_FACTOR;
if (maxZ == null || maxZ < large) {
maxZ = large;
}
return this;
}
@Override
public Bounds addIntersection(
final PlanetModel planetModel,
final Plane plane1,
final Plane plane2,
final Membership... bounds) {
plane1.recordBounds(planetModel, this, plane2, bounds);
return this;
}
@Override
public Bounds addPoint(final GeoPoint point) {
return addXValue(point).addYValue(point).addZValue(point);
}
@Override
public Bounds isWide() {
// No specific thing we need to do.
return this;
}
@Override
public Bounds noLongitudeBound() {
// No specific thing we need to do.
return this;
}
@Override
public Bounds noTopLatitudeBound() {
// No specific thing we need to do.
return this;
}
@Override
public Bounds noBottomLatitudeBound() {
// No specific thing we need to do.
return this;
}
@Override
public Bounds noBound(final PlanetModel planetModel) {
minX = planetModel.getMinimumXValue();
maxX = planetModel.getMaximumXValue();
minY = planetModel.getMinimumYValue();
maxY = planetModel.getMaximumYValue();
minZ = planetModel.getMinimumZValue();
maxZ = planetModel.getMaximumZValue();
return this;
}
/**
* Courtesy method to see if a point is within the bounds.
*
* @param v is the point/vector we want to check
* @return true if the bounds contains the vector
*/
public boolean isWithin(final Vector v) {
return isWithin(v.x, v.y, v.z);
}
/**
* Courtesy method to see if a point is within the bounds.
*
* @param x is the x coordinate
* @param y is the y coordinate
* @param z is the z coordinate
* @return true if the bounds contains the vector
*/
public boolean isWithin(final double x, final double y, final double z) {
return (minX != null
&& x >= minX
&& maxX != null
&& x <= maxX
&& minY != null
&& y >= minY
&& maxY != null
&& y <= maxY
&& minZ != null
&& z >= minZ
&& maxZ != null
&& z <= maxZ);
}
@Override
public String toString() {
return "XYZBounds: [xmin="
+ minX
+ " xmax="
+ maxX
+ " ymin="
+ minY
+ " ymax="
+ maxY
+ " zmin="
+ minZ
+ " zmax="
+ maxZ
+ "]";
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy