package de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.query; /* This file is part of ELKI: Environment for Developing KDD-Applications Supported by Index-Structures Copyright (C) 2012 Ludwig-Maximilians-Universität München Lehr- und Forschungseinheit für Datenbanksysteme ELKI Development Team This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ import java.util.ArrayList; import java.util.Collections; import java.util.List; import de.lmu.ifi.dbs.elki.data.spatial.SpatialComparable; import de.lmu.ifi.dbs.elki.database.ids.DBID; import de.lmu.ifi.dbs.elki.database.query.DistanceResultPair; import de.lmu.ifi.dbs.elki.database.query.DoubleDistanceResultPair; import de.lmu.ifi.dbs.elki.database.query.distance.DistanceQuery; import de.lmu.ifi.dbs.elki.database.query.range.AbstractDistanceRangeQuery; import de.lmu.ifi.dbs.elki.distance.distancefunction.SpatialPrimitiveDoubleDistanceFunction; import de.lmu.ifi.dbs.elki.distance.distancevalue.DoubleDistance; import de.lmu.ifi.dbs.elki.index.tree.DirectoryEntry; import de.lmu.ifi.dbs.elki.index.tree.LeafEntry; import de.lmu.ifi.dbs.elki.index.tree.query.DoubleDistanceSearchCandidate; import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.AbstractRStarTree; import de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.AbstractRStarTreeNode; import de.lmu.ifi.dbs.elki.utilities.datastructures.heap.Heap; import de.lmu.ifi.dbs.elki.utilities.documentation.Reference; /** * Instance of a range query for a particular spatial index. * * Reference: *

* J. Kuan, P. Lewis
* Fast k nearest neighbour search for R-tree family
* In Proc. Int. Conf Information, Communications and Signal Processing, ICICS * 1997 *

* * @author Erich Schubert * * @apiviz.uses AbstractRStarTree * @apiviz.uses SpatialPrimitiveDoubleDistanceFunction */ @Reference(authors = "J. Kuan, P. Lewis", title = "Fast k nearest neighbour search for R-tree family", booktitle = "Proc. Int. Conf Information, Communications and Signal Processing, ICICS 1997", url = "http://dx.doi.org/10.1109/ICICS.1997.652114") public class DoubleDistanceRStarTreeRangeQuery extends AbstractDistanceRangeQuery { /** * The index to use */ protected final AbstractRStarTree tree; /** * Spatial primitive distance function */ protected final SpatialPrimitiveDoubleDistanceFunction distanceFunction; /** * Constructor. * * @param tree Index to use * @param distanceQuery Distance query to use * @param distanceFunction Distance function */ public DoubleDistanceRStarTreeRangeQuery(AbstractRStarTree tree, DistanceQuery distanceQuery, SpatialPrimitiveDoubleDistanceFunction distanceFunction) { super(distanceQuery); this.tree = tree; this.distanceFunction = distanceFunction; } /** * Perform the actual query process. * * @param object Query object * @param epsilon Query range * @return Objects contained in query range. */ protected List> doRangeQuery(O object, double epsilon) { final List> result = new ArrayList>(); final Heap pq = new Heap(); // push root pq.add(new DoubleDistanceSearchCandidate(0.0, tree.getRootID())); // search in tree while(!pq.isEmpty()) { DoubleDistanceSearchCandidate pqNode = pq.poll(); if(pqNode.mindist > epsilon) { break; } AbstractRStarTreeNode node = tree.getNode(pqNode.nodeID); final int numEntries = node.getNumEntries(); for(int i = 0; i < numEntries; i++) { double distance = distanceFunction.doubleMinDist(object, node.getEntry(i)); tree.distanceCalcs++; if(distance <= epsilon) { if(node.isLeaf()) { LeafEntry entry = (LeafEntry) node.getEntry(i); result.add(new DoubleDistanceResultPair(distance, entry.getDBID())); } else { DirectoryEntry entry = (DirectoryEntry) node.getEntry(i); pq.add(new DoubleDistanceSearchCandidate(distance, entry.getEntryID())); } } } } // sort the result according to the distances Collections.sort(result); return result; } @Override public List> getRangeForObject(O obj, DoubleDistance range) { return doRangeQuery(obj, range.doubleValue()); } @Override public List> getRangeForDBID(DBID id, DoubleDistance range) { return getRangeForObject(relation.get(id), range); } }