/* 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.spatial.points; import java.io.File; import java.util.Iterator; import xxl.core.cursors.Cursor; import xxl.core.cursors.Cursors; import xxl.core.cursors.mappers.Mapper; import xxl.core.functions.AbstractFunction; import xxl.core.spatial.cursors.PointInputCursor; import xxl.core.spatial.rectangles.DoublePointRectangle; import xxl.core.spatial.rectangles.FloatPointRectangle; import xxl.core.spatial.rectangles.Rectangle; /** * A utility-class that provides useful static methods for Points like distance methods * and universe computations. * * @see xxl.core.spatial.points.Point * @see xxl.core.spatial.points.FloatPoint * @see xxl.core.spatial.points.DoublePoint * @see xxl.core.spatial.points.FixedPoint * */ public abstract class Points{ /** Computes the L_p-distance of two Points. * * @param p1 Point 1 * @param p2 Point 2 * @param p the value of p * * @return returns the L_p-distance */ public static double lpDistance(Point p1, Point p2, int p){ return Math.pow( lpDistanceWithoutRoot(p1, p2, p), 1.0/p); } /** Computes the L_p-distance of two Points WITHOUT performing the final 1/p power-operation. * * This makes sense in situations where (|p1,p2|)^p is available which is often the case * in ranking algorithms. By using this method one can save calls to the expensive Math.pow-operation. * * @param p1 Point 1 * @param p2 Point 2 * @param p value of p * * @return returns the L_p-distance of two points without performing 1/p power-operation */ public static double lpDistanceWithoutRoot(Point p1, Point p2, int p){ double ret = 0.0; for(int d=0; d<p1.dimensions(); d++){ ret += Math.pow( Math.abs( p1.getValue(d) - p2.getValue(d) ), p ); } return ret; } /** Computes the maximum-distance (=L_\infty-metric) between two given Points. * Calculates the difference between coordinates for each dimension and returns maximum * * @param p1 first Point * @param p2 second Point * * @return returns the maximum coordinate difference for two points given */ public static double maxDistance(Point p1, Point p2){ double ret = 0.0; for(int d=0; d<p1.dimensions(); d++){ ret = Math.max(ret, Math.abs( p1.getValue(d) - p2.getValue(d) )); } return ret; } /** Checks whether the the maximum-distance (=L_\infty-metric) of two Points is less equal than the given distance. * This method will return true if the coordinate difference between the points in * any dimension is not bigger than the given distance * * @param p1 Point 1 * @param p2 Point 2 * @param distance the query distance * * @see xxl.core.predicates.Predicate * @see xxl.core.predicates.DistanceWithin * * @return returns true if the coordinate difference between the points in * any dimension is not bigger than the given distance */ public static boolean withinMaximumDistance(Point p1, Point p2, double distance){ for(int d=0; d<p1.dimensions(); d++){ if( Math.abs( p1.getValue(d) - p2.getValue(d) ) > distance ) return false; } return true; } /** A factory-method that returns an input-Iterator for FixedPoints * of the given dimensionality. * * @param file the input flat file containing the FixedPoints * @param dim the dimensionality of the FixedPoints * * @return returns an input-Iterator for FixedPoints of the given dimensionality. */ public static Cursor newFixedPointInputCursor(final File file, final int dim){ return new PointInputCursor(file, 2, dim); } /** A factory-method that returns an input-Iterator for FloatPoints * of the given dimensionality. * * @param file the input flat file containing the FloatPoints * @param dim the dimensionality of the FloatPoints * * @return returns an input-Iterator for FloatPoints of the given dimensionality. */ public static Cursor newFloatPointInputCursor(final File file, final int dim){ return new PointInputCursor(file, 1, dim); } /** A factory-method that returns an input-Iterator for DoublePoints * of the given dimensionality * * @param file the input flat file containing the DoublePoints * @param dim the dimensionality of the DoublePoints * * @return returns an input-Iterator for DoublePoints of the given dimensionality. */ public static Cursor newDoublePointInputCursor(final File file, final int dim){ return new PointInputCursor(file, 0, dim); } /** Transforms a given Iterator of DoublePoints to the unit-cube [0;1)^dim assuming that * all Points are inside the given universe-DoublePointRectangle and that * the Points are of type DoublePoint. * * @param iterator an Iterator containing DoublePoints * @param universe the minimal bounding rectangle of the Points * * @return cursor returning input DoublePoints converted to to the DoublePoints points in unit-cube [0;1)^dim */ public static Cursor mapToUnitCubeDouble(final Iterator iterator, final Rectangle universe){ return new Mapper( new AbstractFunction(){ protected double[] ll = (double[]) universe.getCorner(false).getPoint(); //lower-left corner protected double[] ur = (double[]) universe.getCorner(true).getPoint(); //upper-right corner public Object invoke(Object object){ double[] point = (double[]) ((Point) ((DoublePoint) object).getPoint()).clone();//clone the input in order to avoid strange side-effects for(int i=0; i < point.length; i++){ //scale to unit-cube: point[i] = (point[i]-ll[i]) / (ur[i]-ll[i]); //new coordinate = point-leftBorder of MBR /(extension of MBR in actual dimension) //ensure that value is in [0;1): point[i] = Math.min(Math.max(0, point[i]), 0.9999999999999999); } return new DoublePoint(point); //create a new DoublePoint (to avoid side-effects); } } , iterator ); } /** Transforms a given Iterator of FloatPoints to the unit-cube [0;1)^dim assuming that * all Points are inside the given universe-FloatPointRectangle and that * the Points are of type FloatPoint. * * @param iterator an Iterator containing FloatPoints * @param universe the minimal bounding rectangle of the Points * * @return cursor returning input FloatPoints converted to to the FloatPoints points in unit-cube [0;1)^dim */ public static Cursor mapToUnitCubeFloat(final Iterator iterator, final Rectangle universe){ return new Mapper( new AbstractFunction(){ protected float[] ll = (float[]) universe.getCorner(false).getPoint(); //lower-left corner protected float[] ur = (float[]) universe.getCorner(true).getPoint(); //upper-right corner public Object invoke(Object object){ float[] point = (float[]) ((Point) ((FloatPoint) object).getPoint()).clone();//clone the input in order to avoid strange side-effects for(int i=0; i < point.length; i++){ //scale to unit-cube: point[i] = (point[i]-ll[i]) / (ur[i]-ll[i]); //new coordinate = point-leftBorder of MBR /(extension of MBR in actual dimension) //ensure that value is in [0;1): point[i] = Math.min(Math.max(0, point[i]), 0.999999f); } return new FloatPoint(point); //create a new FloatPoint (to avoid side-effects); } } , iterator ); } /** Computes the minimal bounding rectangle (i.e. the "universe") of an Iterator of DoublePoint-objects. * Note that this method is blocking since it has to consume the entire input-Iterator * in order to compute the minimal bounding rectangle of the Points. * * @param input an Iterator containing DoublePoints * @return returns DoublePointRectangle which is the MBR of the points given */ public static Rectangle universeDouble(final Iterator input){ if(!input.hasNext()) throw new IllegalArgumentException("input-Iterator is empty!"); Cursor cursor = Cursors.wrap(input); final int dim = ((DoublePoint)cursor.peek()).dimensions(); double[] ll = (double[]) ((Point) ((DoublePoint)cursor.peek()).getPoint()).clone(); double[] ur = (double[]) ((Point) ((DoublePoint)cursor.peek()).getPoint()).clone(); while(input.hasNext()){ double[] point = (double[]) ((DoublePoint)input.next()).getPoint(); for(int i=0; i<dim; i++){ ll[i] = Math.min(ll[i], point[i]); ur[i] = Math.max(ur[i], point[i]); } } DoublePoint llp = new DoublePoint(ll); DoublePoint urp = new DoublePoint(ur); return new DoublePointRectangle(llp, urp); //return the computed universe } /** Computes the minimal bounding rectangle (i.e. the "universe") of an Iterator of FloatPoint-objects. * Note that this method is blocking since it has to consume the entire input-Iterator * in order to compute the minimal bounding rectangle of the Points. * * @param input an Iterator containing FloatPoints * @return returns FloatPointRectangle which is the MBR of the points given */ public static Rectangle universeFloat(final Iterator input){ if(!input.hasNext()) throw new IllegalArgumentException("input-Iterator is empty!"); Cursor cursor = Cursors.wrap(input); final int dim = ((FloatPoint)cursor.peek()).dimensions(); float[] ll = (float[]) ((Point) ((FloatPoint)cursor.peek()).getPoint()).clone(); float[] ur = (float[]) ((Point) ((FloatPoint)cursor.peek()).getPoint()).clone(); while(input.hasNext()){ float[] point = (float[]) ((FloatPoint)input.next()).getPoint(); for(int i=0; i<dim; i++){ ll[i] = Math.min(ll[i], point[i]); ur[i] = Math.max(ur[i], point[i]); } } FloatPoint llp = new FloatPoint(ll); FloatPoint urp = new FloatPoint(ur); return new FloatPointRectangle(llp, urp); //return the computed universe } }