/* XXL: The eXtensible and fleXible Library for data processing
Copyright (C) 2000-2011 Prof. Dr. Bernhard Seeger
Head of the Database Research Group
Department of Mathematics and Computer Science
University of Marburg
Germany
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; If not, see <http://www.gnu.org/licenses/>.
http://code.google.com/p/xxl/
*/
package xxl.core.indexStructures;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import xxl.core.functions.AbstractFunction;
import xxl.core.functions.Function;
import xxl.core.io.Convertable;
import xxl.core.io.converters.Converter;
import xxl.core.io.converters.DoubleConverter;
import xxl.core.spatial.LpMetric;
import xxl.core.util.Distance;
/**
* This class implements a {@link xxl.core.indexStructures.Descriptor} that is a sphere.
* This class is used in the @link xxl.core.indexStructures.MTree MTree}.
*
*/
public class Sphere implements Descriptor, Convertable {
protected static final double DEFAULT_DISTANCE_TO_PARENT = -1;
protected static final Distance DEFAULT_POINT_DISTANCE = LpMetric.EUCLIDEAN;
protected static final Distance DEFAULT_SPHERE_DISTANCE = SphereMinimumDistance.DEFAULT_INSTANCE;
/** The center of the sphere.
*/
protected Object center;
/** The radius if the sphere.
*/
protected double radius;
/** A suitable converter for the center of the sphere.
*/
protected Converter centerConverter;
/** The distance from the center of this sphere to the center of the
* sphere of the parent node in the MTree.
*/
protected double distanceToParent = -1;
/** The metric distance function for points.
*/
protected Distance pointDistance;
/** The metric distance function for spheres.
*/
protected Distance sphereDistance;
/** Creates a new sphere.
*
* @param center the new {@link Sphere#center}
* @param radius the new {@link Sphere#radius}
* @param centerConverter the new {@link Sphere#centerConverter}
* @param distanceToParent the new {@link Sphere#distanceToParent}
* @param pointDistance the new {@link #pointDistance}
* @param sphereDistance the new {@link #sphereDistance}
*/
public Sphere (Object center, double radius, Converter centerConverter, double distanceToParent, Distance pointDistance, Distance sphereDistance) {
this.center = center;
this.radius = radius;
this.centerConverter = centerConverter;
this.distanceToParent = distanceToParent;
this.pointDistance = pointDistance;
this.sphereDistance = sphereDistance;
}
/** Creates a new sphere.
*
* @param center the new {@link Sphere#center}
* @param radius the new {@link Sphere#radius}
* @param centerConverter the new {@link Sphere#centerConverter}
* @param distanceToParent the new {@link Sphere#distanceToParent}
*/
public Sphere (Object center, double radius, Converter centerConverter, double distanceToParent) {
this(center, radius, centerConverter, distanceToParent, DEFAULT_POINT_DISTANCE, DEFAULT_SPHERE_DISTANCE);
}
/** Creates a new sphere.
*
* @param center the new {@link Sphere#center}
* @param radius the new {@link Sphere#radius}
* @param centerConverter the new {@link Sphere#centerConverter}
* @param distanceToParent the new {@link Sphere#distanceToParent}
* @param pointDistance the new {@link #pointDistance}
*/
public Sphere (Object center, double radius, Converter centerConverter, double distanceToParent, Distance pointDistance) {
this(center, radius, centerConverter, distanceToParent, pointDistance, DEFAULT_SPHERE_DISTANCE);
}
/** Creates a new sphere by calling
* <pre><code>
this(center, radius, centerConverter, -1);
</code></pre>
*
* @param center the new {@link Sphere#center}
* @param radius the new {@link Sphere#radius}
* @param centerConverter the new {@link Sphere#centerConverter}
* @param pointDistance the new {@link #pointDistance}
* @param sphereDistance the new {@link #sphereDistance}
*/
public Sphere (Object center, double radius, Converter centerConverter, Distance pointDistance, Distance sphereDistance) {
this(center, radius, centerConverter, DEFAULT_DISTANCE_TO_PARENT, pointDistance, sphereDistance);
}
/** Creates a new sphere.
*
* @param center the new {@link Sphere#center}
* @param radius the new {@link Sphere#radius}
* @param centerConverter the new {@link Sphere#centerConverter}
*/
public Sphere (Object center, double radius, Converter centerConverter) {
this(center, radius, centerConverter, DEFAULT_DISTANCE_TO_PARENT);
}
/* (non-Javadoc)
* @see xxl.core.io.Convertable#write(java.io.DataOutput)
*/
public void write (DataOutput dataOutput) throws IOException {
centerConverter.write(dataOutput, center);
DoubleConverter.DEFAULT_INSTANCE.writeDouble(dataOutput,radius);
DoubleConverter.DEFAULT_INSTANCE.writeDouble(dataOutput, distanceToParent);
}
/* (non-Javadoc)
* @see xxl.core.io.Convertable#read(java.io.DataInput)
*/
public void read (DataInput dataInput) throws IOException {
center = centerConverter.read(dataInput);
radius = DoubleConverter.DEFAULT_INSTANCE.readDouble(dataInput);
distanceToParent = DoubleConverter.DEFAULT_INSTANCE.readDouble(dataInput);
}
/** Computes the distance between the center of this and the center of the
* specified <tt>sphere</tt> using the {@link MTree#pointDistance}.
*
* @param sphere the sphere to whichs center the distance should be determined
* @return the distance between the center of this and the center of <tt>sphere</tt>
*/
public double centerDistance (Sphere sphere) {
return pointDistance.distance(center, sphere.center);
}
/** Computes the distance between this and the
* specified <tt>sphere</tt> using the {@link MTree#sphereDistance}.
*
* @param sphere the sphere to which the distance should be determined
* @return the distance between this and <tt>sphere</tt>
*/
public double sphereDistance (Sphere sphere) {
return overlapsPD(sphere) ? 0 : sphereDistance.distance(this, sphere);
}
/** Returns <tt>true</tt> if this sphere overlaps the specified sphere.
*
* @param descriptor the sphere to check
* @return <tt>true</tt> if this sphere overlaps the specified sphere
*/
public boolean overlaps (Descriptor descriptor) {
Sphere sphere = (Sphere)descriptor;
return centerDistance(sphere) <= radius + sphere.radius;
}
/** Returns <tt>true</tt> if this sphere overlaps the specified sphere.
* This implementation uses an optimization: If the difference of
* distances to the center of the parent node of the spheres is greater
* than the sum of their radiuses, the spheres cannot overlap. This
* case can be detected using
* {@link Sphere#distanceToParent}.
*
* @param descriptor the sphere to check
* @return <tt>true</tt> if this sphere overlaps the specified sphere
*/
public boolean overlapsPD (Descriptor descriptor) {
Sphere sphere = (Sphere)descriptor;
if (sphere.distanceToParent != -1 && distanceToParent != -1)
if (Math.abs(sphere.distanceToParent - distanceToParent) > (sphere.radius + radius))
return false;
return overlaps(sphere);
}
/** Returns <tt>true</tt> if this sphere contains the specified sphere.
*
* @param descriptor the sphere to check
* @return <tt>true</tt> if this sphere contains the specified sphere
*/
public boolean contains (Descriptor descriptor) {
Sphere sphere = (Sphere)descriptor;
return centerDistance(sphere) + sphere.radius <= radius;
}
/** Returns <tt>true</tt> if this sphere contains the specified sphere.
* This implementation uses an optimization: If the difference of
* distances to the center of the parent node of the spheres is greater
* than the sum of their radiuses, the spheres cannot overlap and i.e.
* not contain each other. This case can be detected using
* {@link Sphere#distanceToParent}.
*
* @param descriptor the sphere to check
* @return <tt>true</tt> if this sphere contains the specified sphere
*/
public boolean containsPD (Descriptor descriptor) {
Sphere sphere = (Sphere)descriptor;
if (sphere.distanceToParent != -1 && distanceToParent != -1)
if (Math.abs(sphere.distanceToParent - distanceToParent) > (sphere.radius + radius))
return false;
return contains(sphere);
}
/* (non-Javadoc)
* @see xxl.core.indexStructures.Descriptor#union(xxl.core.indexStructures.Descriptor)
*/
public void union (Descriptor descriptor) {
Sphere sphere = (Sphere)descriptor;
radius = Math.max(radius, centerDistance(sphere) + sphere.radius);
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals (Object object) {
Sphere sphere = (Sphere)object;
return center.equals(sphere.center) && radius == sphere.radius;
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
return center.hashCode();
}
/* (non-Javadoc)
* @see java.lang.Object#clone()
*/
public Object clone () {
return new Sphere(center, radius, centerConverter, distanceToParent, pointDistance, sphereDistance);
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
public String toString () {
String s = "center: "+"("+center.toString()+")";
s += "\tradius: "+radius;
s += "\tdistance to parent: "+distanceToParent;
return s;
}
/** Returns the center of this sphere.
*
* @return the center of this sphere
*/
public Object center () {
return center;
}
/** Returns the radius of this sphere.
*
* @return the radius of this sphere
*/
public double radius () {
return radius;
}
/** Returns the center converter
*
* @return center converter
*/
public Converter getCenterConverter() {
return this.centerConverter;
}
/** Returns the point distance
*
* @return point distance
*/
public Distance getPointDistance() {
return this.pointDistance;
}
/** Returns the sphere distance
*
* @return sphere distance
*/
public Distance getSphereDistance() {
return this.sphereDistance;
}
/** Returns the distance from the center of this node to the center of
* the parent node.
*
* @return the distance to the center of the parent node
*/
public double getDistanceToParent() {
return distanceToParent;
}
/** Sets the distance from the center of this node to the center of the parent node.
*
* @param distanceToParent distance from the center of this node to the center of the parent node
*/
public void setDistanceToParent(double distanceToParent) {
this.distanceToParent = distanceToParent;
}
/** Returns a function, which constructs Spheres by the given argument. It only needs to know,
* which Converter should be used for the storage of the data points.
*
* @param dataPointConverter converter for data points in the constructed Spheres.
* @return Function for creating Spheres
*/
public static <T> Function<T, Sphere> getFactoryFunction(final Converter<? super T> dataPointConverter) {
return new AbstractFunction<T, Sphere>() {
public Sphere invoke(T pointToStore) {
return new Sphere(pointToStore, 0.0, dataPointConverter);
}
};
}
/** Returns a function, which constructs Spheres by the given argument. It only needs to know,
* which Converter should be used for the storage of the data points.
*
* @param dataPointConverter converter for data points in the constructed Spheres.
* @param dataPointDistance distance between data points
* @return Function for creating Spheres
*/
public static <T> Function<T, Sphere> getFactoryFunction(final Converter<? super T> dataPointConverter, final Distance<? super T> dataPointDistance) {
return new AbstractFunction<T, Sphere>() {
public Sphere invoke(T pointToStore) {
return new Sphere(pointToStore, 0.0, dataPointConverter, dataPointDistance, SphereMinimumDistance.DEFAULT_INSTANCE);
}
};
}
/**
* A class for computing the minimum distance between Spheres. See {@link Distance} for general information
* about Distances.
*/
public static class SphereMinimumDistance implements Distance<Sphere> {
public static SphereMinimumDistance DEFAULT_INSTANCE = new SphereMinimumDistance();
@Override
public double distance (Sphere s1, Sphere s2) {
return Math.abs(s1.centerDistance(s2) - s1.radius() - s2.radius());
}
}
/**
* A class for computing the distance between the centers of Spheres. See {@link Distance} for general information
* about Distances.
*/
public static class SphereCenterDistance implements Distance<Sphere> {
public static SphereCenterDistance DEFAULT_INSTANCE = new SphereCenterDistance();
@Override
public double distance (Sphere s1, Sphere s2) {
return s1.centerDistance(s2);
}
}
} // end of class Sphere