/* 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.cursors; import java.util.Iterator; import xxl.core.cursors.Cursor; import xxl.core.cursors.mappers.Mapper; import xxl.core.functions.AbstractFunction; import xxl.core.functions.Function; import xxl.core.spatial.KPE; import xxl.core.spatial.KPEzCode; import xxl.core.spatial.SpaceFillingCurves; import xxl.core.spatial.points.DoublePoint; import xxl.core.spatial.points.FloatPoint; import xxl.core.spatial.points.Point; import xxl.core.spatial.rectangles.DoublePointRectangle; import xxl.core.spatial.rectangles.FixedPointRectangle; import xxl.core.spatial.rectangles.FloatPointRectangle; import xxl.core.spatial.rectangles.Rectangle; /** * This class provides several static methods returning suitable Mappers * for the spatial context. * * @see xxl.core.cursors.mappers.Mapper */ public class Mappers { /** Don't let anyone instantiate this class. */ private Mappers() {} /** Returns a Mapper mapping an Iterator of DoublePoints to * an Iterator of FloatPoints. * * @param iterator an input iterator containing DoublePoints * @return a mapper mapping DoublePoints to FloatPoints */ public static Cursor<FloatPoint> mapPointToFloatPoint(final Iterator<? extends Point> iterator) { return new Mapper<Point, FloatPoint>( new AbstractFunction<Point, FloatPoint>() { public FloatPoint invoke(Point point) { float[] vector = new float[point.dimensions()]; for(int i = 0; i < vector.length; i++) vector[i] = (float)point.getValue(i); return new FloatPoint(vector); } }, iterator ); } /** Returns a Mapper mapping an Iterator of FloatPoints to * an Iterator of DoublePoints. * * @param iterator an input iterator containing FloatPoints * @return a mapper mapping FloatPoints to DoublePoints */ public static Cursor<DoublePoint> mapPointToDoublePoint(final Iterator<? extends Point> iterator){ return new Mapper<Point, DoublePoint>( new AbstractFunction<Point, DoublePoint>() { public DoublePoint invoke(Point point){ double[] vector = new double[point.dimensions()]; for (int i = 0; i < vector.length; i++) vector[i] = point.getValue(i); return new DoublePoint(vector); } }, iterator ); } /** * Return a mapper mapping an input iterator of KPEs containing * a Rectangle as data item to Points. This is useful if one wants to extract * Points from an existing data set of spatial data. * * @param iterator an input iterator containing KPEs * @param corner boolean flag determining which corner should be returned by the mapping function * @return a mapper mapping KPEs to FloatPoints */ public static Cursor<FloatPoint> mapKPEToFloatPoint(Iterator<? extends KPE> iterator, final boolean corner) { return mapPointToFloatPoint( new Mapper<KPE, Point>( new AbstractFunction<KPE, Point>() { public Point invoke(KPE kpe) { return ((Rectangle)kpe.getData()).getCorner(corner); } }, iterator ) ); } /** Return a mapper extracting data objects from a given Iterator of KPEs. * This is performed by calling the <tt>getData()</tt> method on each input object. * * @param iterator an input iterator containing KPEs * @return a mapper mapping KPEs to the included data objects */ public static Cursor<Object> mapKPEToData(final Iterator<? extends KPE> iterator) { return new Mapper<KPE, Object>( new AbstractFunction<KPE, Object>() { public Object invoke(KPE kpe) { return kpe.getData(); } }, iterator ); } /** * Returns a function converting a FloatPoint to a FloatPointRectangle where * the point is the center of the rectangle * 2*epsilon x 2*epsilon x ... x 2*epsilon. * The input-Points are assumed to be inside the unit-cube. * * @param epsilon the epsilon distance (Note: rectangles of side length 2*epsilon are created) * @return a function converting Points to FixedPointRectangles */ public static Function<Point, DoublePointRectangle> pointToDoublePointRectangleMappingFunction(final double epsilon) { return new AbstractFunction<Point, DoublePointRectangle>() { public DoublePointRectangle invoke(Point point) { double[] ll = new double[point.dimensions()]; double[] ur = new double[ll.length]; for (int i = 0; i < ll.length; i++) { ll[i] = Math.max(0.0f, point.getValue(i)-epsilon); //check lower border ur[i] = Math.min(0.9999999f, point.getValue(i)+epsilon); //check upper border } return new DoublePointRectangle(ll, ur); } }; } /** * Returns a Mapper mapping a FloatPoint to a FloatPointRectangle * where the point is the center of the rectangle * 2*epsilon x 2*epsilon x ... x 2*epsilon. * * @param iterator an Iterator containing FloatPoints * @param epsilon the epsilon distance (Note: rectangles of side length 2*epsilon are created) * @return a mapper mapping FloatPoints to FloatPointRectangles */ public static Cursor<DoublePointRectangle> mapPointToDoublePointRectangle(Iterator<? extends Point> iterator, float epsilon) { return new Mapper<Point, DoublePointRectangle>( pointToDoublePointRectangleMappingFunction(epsilon), iterator ); } /** * Returns a function converting a FloatPoint to a FloatPointRectangle where * the point is the center of the rectangle * 2*epsilon x 2*epsilon x ... x 2*epsilon. * The input-Points are assumed to be inside the unit-cube. * * @param epsilon the epsilon distance (Note: rectangles of side length 2*epsilon are created) * @return a function converting Points to FixedPointRectangles */ public static Function<Point, FloatPointRectangle> pointToFloatPointRectangleMappingFunction(final float epsilon) { return new AbstractFunction<Point, FloatPointRectangle>() { public FloatPointRectangle invoke(Point point) { float[] ll = new float[point.dimensions()]; float[] ur = new float[ll.length]; for (int i = 0; i < ll.length; i++) { ll[i] = Math.max(0.0f, (float)(point.getValue(i)-epsilon)); //check lower border ur[i] = Math.min(0.9999999f, (float)(point.getValue(i)+epsilon)); //check upper border } return new FloatPointRectangle(ll, ur); } }; } /** * Returns a Mapper mapping a FloatPoint to a FloatPointRectangle * where the point is the center of the rectangle * 2*epsilon x 2*epsilon x ... x 2*epsilon. * * @param iterator an Iterator containing FloatPoints * @param epsilon the epsilon distance (Note: rectangles of side length 2*epsilon are created) * @return a mapper mapping FloatPoints to FloatPointRectangles */ public static Cursor<FloatPointRectangle> mapPointToFloatPointRectangle(Iterator<? extends Point> iterator, float epsilon) { return new Mapper<Point, FloatPointRectangle>( pointToFloatPointRectangleMappingFunction(epsilon), iterator ); } /** * Returns a Mapper mapping incoming FloatPoints to an Iterator of * <tt>KPEzCodes</tt> containing a rectangle (of type Rectangle) as well as the corresponding z-code * (of type <tt>BitSet</tt>). * <br> * This means, for each input FloatPoint this class computes * * <ol> * <li> a Rectangle with length * epsilon in each dimension. The incoming FloatPoint is the center of the latter rectangle. * <li> the z-code of that rectangle * </ol> * * Both objects are contained in a specialized ConvertableTuple called KPEzCode which is returned by this Mapper. * * @param iterator an Iterator containing FloatPoints * @param epsilon extension of the rectangles to be created in each dimension * @param maxLevel the maximum level to be used for the z-code computation * @return a mapper mapping FloatPoints to KPEzCodes */ public static Function<Point, KPEzCode> pointToKPEzCodeMappingFunction(final float epsilon, final int maxLevel) { return new AbstractFunction<Point, KPEzCode>() { protected int count = 0; protected Function<Point, FloatPointRectangle> epsilonMapping = pointToFloatPointRectangleMappingFunction(epsilon/2); public KPEzCode invoke(Point point){ return new KPEzCode(point, count++, SpaceFillingCurves.zCode(epsilonMapping.invoke(point), maxLevel)); } }; } /** * Returns a Mapper mapping incoming FloatPoints to an Iterator of * <tt>KPEzCodes</tt> containing a rectangle (of type Rectangle) as well as the corresponding z-code * (of type <tt>BitSet</tt>). * <br> * This means, for each input FloatPoint this class computes * * <ol> * <li> a Rectangle with length * epsilon in each dimension. The incoming FloatPoint is the center of the latter rectangle. * <li> the z-code of that rectangle * </ol> * * Both objects are contained in a specialized ConvertableTuple called KPEzCode which is returned by this Mapper. * * @param iterator an Iterator containing FloatPoints * @param epsilon extension of the rectangles to be created in each dimension * @param maxLevel the maximum level to be used for the z-code computation * @return a mapper mapping FloatPoints to KPEzCodes */ public static Cursor<KPEzCode> mapPointToKPEzCode(Iterator<? extends Point> iterator, float epsilon, int maxLevel) { return new Mapper<Point, KPEzCode>( pointToKPEzCodeMappingFunction(epsilon, maxLevel), iterator ); } /** * Returns a function converting a Point to a FixedPointRectangle where * the point is the center of the rectangle * 2*epsilon x 2*epsilon x ... x 2*epsilon. * The input-Points are assumed to be inside the unit-cube. * * @param epsilon the epsilon distance (Note: rectangles of side length 2*epsilon are created) * @return a function converting Points to FixedPointRectangles */ public static Function<Point, FixedPointRectangle> pointToFixedPointRectangleMappingFunction(final double epsilon) { return new AbstractFunction<Point, FixedPointRectangle>() { public FixedPointRectangle invoke(Point point) { long[] ll = new long[point.dimensions()]; long[] ur = new long[ll.length]; for (int i = 0; i < ll.length; i++) { ll[i] = xxl.core.math.Maths.doubleToNormalizedLongBits(Math.max(0.0d, point.getValue(i)-epsilon)); //check lower border ur[i] = xxl.core.math.Maths.doubleToNormalizedLongBits(Math.min(0.9999999999999999d, point.getValue(i)+epsilon)); //check upper border } return new FixedPointRectangle(ll, ur); } }; } /** * Returns a Mapper mapping a Point to a FixedPointRectangle where * the point is the center of the rectangle * 2*epsilon x 2*epsilon x ... x 2*epsilon. * The input-Points are assumed to be inside the unit-cube. * * @param iterator an Iterator containing Points * @param epsilon the epsilon distance (Note: rectangles of side length 2*epsilon are created) * @return a mapper mapping Points to FixedPointRectangles * * @see #getPointFixedPointRectangleMappingFunction(double) */ public static Cursor<FixedPointRectangle> mapPointToFixedPointRectangle(Iterator<? extends Point> iterator, double epsilon) { return new Mapper<Point, FixedPointRectangle>( pointToFixedPointRectangleMappingFunction(epsilon), iterator ); } /** Returns a Mapper transforming 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. * This is an important pre-processing step needed e.g. for hihg-dimensional data. * * @param iterator an Iterator containing FloatPoints * @param universe the minimal bounding rectangle of the Points * @return a mapper mapping FloatPoints to into the unit-cube */ public static Cursor<FloatPoint> mapPointToUnitCube(Iterator<? extends Point> iterator, final Rectangle universe) { return new Mapper<Point, FloatPoint>( new AbstractFunction<Point, FloatPoint>() { protected Point ll = universe.getCorner(false); //lower-left corner protected Point ur = universe.getCorner(true); //upper-right corner public FloatPoint invoke(Point point) { float[] vector = new float[point.dimensions()]; for (int i = 0; i < vector.length; i++) { //scale to unit-cube: vector[i] = (float)((point.getValue(i)-ll.getValue(i)) / (ur.getValue(i)-ll.getValue(i))); //new coordinate = point-leftBorder of MBR /(extension of MBR in actual dimension) //ensure that value is in [0;1): vector[i] = Math.min(Math.max(0, (float)point.getValue(i)), 0.999999f); } return new FloatPoint(vector); //create a new FloatPoint (to avoid side-effects); } }, iterator ); } }