/// <summary> /// Finds the item in this tree which is nearest to the given <paramref name="item"/>, /// using <see cref="IItemDistance{Envelope,TItem}"/> as the distance metric. /// A Branch-and-Bound tree traversal algorithm is used /// to provide an efficient search. /// <para/> /// The query <paramref name="item"/> does <b>not</b> have to be /// contained in the tree, but it does /// have to be compatible with the <paramref name="itemDist"/> /// distance metric. /// </summary> /// <param name="env">The envelope of the query item</param> /// <param name="item">The item to find the nearest neighbour of</param> /// <param name="itemDist">A distance metric applicable to the items in this tree and the query item</param> /// <returns>The nearest item in this tree</returns> public TItem NearestNeighbour(Envelope env, TItem item, IItemDistance <Envelope, TItem> itemDist) { var bnd = new ItemBoundable <Envelope, TItem>(env, item); var bp = new BoundablePair <TItem>(Root, bnd, itemDist); return(NearestNeighbour(bp)[0]); }
/// <inheritdoc cref="IComparer{T}.Compare"/> public int Compare(BoundablePair <TItem> p1, BoundablePair <TItem> p2) { var distance1 = p1.Distance; var distance2 = p2.Distance; if (_normalOrder) { if (distance1 > distance2) { return(1); } if (distance1 == distance2) { return(0); } return(-1); } else { if (distance1 > distance2) { return(-1); } else if (distance1 == distance2) { return(0); } return(1); } }
/// <summary> /// Compares two pairs based on their minimum distances /// </summary> public int CompareTo(BoundablePair <TItem> o) { if (_distance < o._distance) { return(-1); } if (_distance > o._distance) { return(1); } return(0); }
private void Expand(IBoundable <Envelope, TItem> bndComposite, IBoundable <Envelope, TItem> bndOther, PriorityQueue <BoundablePair <TItem> > priQ, double minDistance) { var children = ((AbstractNode <Envelope, TItem>)bndComposite).ChildBoundables; foreach (var child in children) { var bp = new BoundablePair <TItem>(child, bndOther, _itemDistance); // only add to queue if this pair might contain the closest points // MD - it's actually faster to construct the object rather than called distance(child, bndOther)! if (bp.Distance < minDistance) { priQ.Add(bp); } } }
private TItem[] NearestNeighbour(BoundablePair <TItem> initBndPair, double maxDistance, int k) { var distanceLowerBound = maxDistance; // initialize internal structures var priQ = new PriorityQueue <BoundablePair <TItem> >(); // initialize queue priQ.Add(initBndPair); var kNearestNeighbors = new PriorityQueue <BoundablePair <TItem> >(k, new BoundablePairDistanceComparer <TItem>(false)); while (!priQ.IsEmpty() && distanceLowerBound >= 0.0) { // pop head of queue and expand one side of pair var bndPair = priQ.Poll(); var currentDistance = bndPair.Distance; /** * If the distance for the first node in the queue * is >= the current maximum distance in the k queue , all other nodes * in the queue must also have a greater distance. * So the current minDistance must be the true minimum, * and we are done. */ if (currentDistance >= distanceLowerBound) { break; } /** * If the pair members are leaves * then their distance is the exact lower bound. * Update the distanceLowerBound to reflect this * (which must be smaller, due to the test * immediately prior to this). */ if (bndPair.IsLeaves) { // assert: currentDistance < minimumDistanceFound if (kNearestNeighbors.Size < k) { kNearestNeighbors.Add(bndPair); } else { if (kNearestNeighbors.Peek().Distance > currentDistance) { kNearestNeighbors.Poll(); kNearestNeighbors.Add(bndPair); } /* * minDistance should be the farthest point in the K nearest neighbor queue. */ distanceLowerBound = kNearestNeighbors.Peek().Distance; } } else { // testing - does allowing a tolerance improve speed? // Ans: by only about 10% - not enough to matter /* * double maxDist = bndPair.getMaximumDistance(); * if (maxDist * .99 < lastComputedDistance) * return; * //*/ /** * Otherwise, expand one side of the pair, * (the choice of which side to expand is heuristically determined) * and insert the new expanded pairs into the queue */ bndPair.ExpandToQueue(priQ, distanceLowerBound); } } // done - return items with min distance return(GetItems(kNearestNeighbors)); }
private static TItem[] NearestNeighbour(BoundablePair <TItem> initBndPair, double maxDistance) { var distanceLowerBound = maxDistance; BoundablePair <TItem> minPair = null; // initialize internal structures var priQ = new PriorityQueue <BoundablePair <TItem> >(); // initialize queue priQ.Add(initBndPair); while (!priQ.IsEmpty() && distanceLowerBound > 0.0) { // pop head of queue and expand one side of pair var bndPair = priQ.Poll(); var currentDistance = bndPair.Distance; //bndPair.GetDistance(); /** * If the distance for the first node in the queue * is >= the current minimum distance, all other nodes * in the queue must also have a greater distance. * So the current minDistance must be the true minimum, * and we are done. */ if (currentDistance >= distanceLowerBound) { break; } /** * If the pair members are leaves * then their distance is the exact lower bound. * Update the distanceLowerBound to reflect this * (which must be smaller, due to the test * immediately prior to this). */ if (bndPair.IsLeaves) { // assert: currentDistance < minimumDistanceFound distanceLowerBound = currentDistance; minPair = bndPair; } else { // testing - does allowing a tolerance improve speed? // Ans: by only about 10% - not enough to matter /* * double maxDist = bndPair.getMaximumDistance(); * if (maxDist * .99 < lastComputedDistance) * return; * //*/ /** * Otherwise, expand one side of the pair, * (the choice of which side to expand is heuristically determined) * and insert the new expanded pairs into the queue */ bndPair.ExpandToQueue(priQ, distanceLowerBound); } } if (minPair != null) { // done - return items with min distance return new[] { ((ItemBoundable <Envelope, TItem>)minPair.GetBoundable(0)).Item, ((ItemBoundable <Envelope, TItem>)minPair.GetBoundable(1)).Item } } ; return(null); }
private TItem[] NearestNeighbour(BoundablePair <TItem> initBndPair, int k) { return(NearestNeighbour(initBndPair, double.PositiveInfinity, k)); }
private static TItem[] NearestNeighbour(BoundablePair <TItem> initBndPair) { return(NearestNeighbour(initBndPair, Double.PositiveInfinity)); }
/// <summary> /// Finds the two nearest items from this tree /// and another tree, /// using <see cref="IItemDistance{Envelope, TItem}"/> as the distance metric. /// A Branch-and-Bound tree traversal algorithm is used /// to provide an efficient search. /// The result value is a pair of items, /// the first from this tree and the second /// from the argument tree. /// </summary> /// <param name="tree">Another tree</param> /// <param name="itemDist">A distance metric applicable to the items in the trees</param> /// <returns>The pair of the nearest items, one from each tree</returns> public TItem[] NearestNeighbour(STRtree <TItem> tree, IItemDistance <Envelope, TItem> itemDist) { var bp = new BoundablePair <TItem>(Root, tree.Root, itemDist); return(NearestNeighbour(bp)); }