/// <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]); }
private void Expand(IBoundable <Envelope, TItem> bndComposite, IBoundable <Envelope, TItem> bndOther, bool isFlipped, PriorityQueue <BoundablePair <TItem> > priQ, double minDistance) { var children = ((AbstractNode <Envelope, TItem>)bndComposite).ChildBoundables; foreach (var child in children) { BoundablePair <TItem> bp; if (isFlipped) { bp = new BoundablePair <TItem>(bndOther, child, _itemDistance); } else { 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); } } }
/// <inheritdoc cref="IComparer{T}.Compare"/> public int Compare(BoundablePair <TItem> p1, BoundablePair <TItem> p2) { double distance1 = p1.Distance; double 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> /// 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 or <c>null</c> if no pair of distinct items can be found.</returns> public TItem[] NearestNeighbour(STRtree <TItem> tree, IItemDistance <Envelope, TItem> itemDist) { if (IsEmpty || tree.IsEmpty) { return(null); } var bp = new BoundablePair <TItem>(Root, tree.Root, itemDist); return(NearestNeighbour(bp)); }
/// <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); }
/// <summary> /// Finds the two nearest items in the 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. /// <para/> /// If the tree is empty, the return value is <c>null</c>. /// If the tree contains only one item, the return value is a pair containing that item. /// If it is required to find only pairs of distinct items, /// the <see cref="IItemDistance{T,TItem}"/> function must be <b>anti-reflexive</b>. /// </summary> /// <param name="itemDist">A distance metric applicable to the items in this tree</param> /// <returns>The pair of the nearest items or <c>null</c> if the tree is empty</returns> public TItem[] NearestNeighbour(IItemDistance <Envelope, TItem> itemDist) { if (IsEmpty) { return(null); } // if tree has only one item this will return null var bp = new BoundablePair <TItem>(Root, Root, itemDist); return(NearestNeighbour(bp)); }
private TItem[] NearestNeighbour(BoundablePair <TItem> initBndPair, double maxDistance, int k) { double 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(); double 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) { double 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(); double 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 in the 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. /// </summary> /// <param name="itemDist">A distance metric applicable to the items in this tree</param> /// <returns>The pair of the nearest items</returns> public TItem[] NearestNeighbour(IItemDistance <Envelope, TItem> itemDist) { var bp = new BoundablePair <TItem>(Root, Root, itemDist); return(NearestNeighbour(bp)); }
/** * Performs a withinDistance search on the tree node pairs. * This is a different search algorithm to nearest neighbour. * It can utilize the {@link BoundablePair#maximumDistance()} between * tree nodes to confirm if two internal nodes must * have items closer than the maxDistance, * and short-circuit the search. * * @param initBndPair the initial pair containing the tree root nodes * @param maxDistance the maximum distance to search for * @return true if two items lie within the given distance */ private bool IsWithinDistance(BoundablePair <TItem> initBndPair, double maxDistance) { double distanceUpperBound = double.PositiveInfinity; // initialize search queue var priQ = new PriorityQueue <BoundablePair <TItem> >(); priQ.Add(initBndPair); while (!priQ.IsEmpty()) { // pop head of queue and expand one side of pair var bndPair = priQ.Poll(); double pairDistance = bndPair.Distance; /** * If the distance for the first pair in the queue * is > maxDistance, other pairs * in the queue must also have a greater distance. * So can conclude no items are within the distance * and terminate with result = false */ if (pairDistance > maxDistance) { return(false); } /** * If the maximum distance between the nodes * is less than the maxDistance, * than all items in the nodes must be * closer than the max distance. * Then can terminate with result = true. * * NOTE: using Envelope MinMaxDistance * would provide a tighter bound, * but not much performance improvement has been observed */ if (bndPair.MaximumDistance() <= maxDistance) { return(true); } /** * If the pair items are leaves * then their actual distance is an upper bound. * Update the distanceUpperBound to reflect this */ if (bndPair.IsLeaves) { // assert: currentDistance < minimumDistanceFound distanceUpperBound = pairDistance; /** * If the items are closer than maxDistance * can terminate with result = true. */ if (distanceUpperBound <= maxDistance) { return(true); } } else { /** * Otherwise, expand one side of the pair, * and insert the expanded pairs into the queue. * The choice of which side to expand is determined heuristically. */ bndPair.ExpandToQueue(priQ, distanceUpperBound); } } return(false); }
/** * Tests whether some two items from this tree and another tree * lie within a given distance. * {@link ItemDistance} is used as the distance metric. * A Branch-and-Bound tree traversal algorithm is used * to provide an efficient search. * * @param tree another tree * @param itemDist a distance metric applicable to the items in the trees * @param maxDistance the distance limit for the search * @return true if there are items within the distance */ public bool IsWithinDistance(STRtree <TItem> tree, IItemDistance <Envelope, TItem> itemDist, double maxDistance) { var bp = new BoundablePair <TItem>(Root, tree.Root, itemDist); return(IsWithinDistance(bp, maxDistance)); }
private static TItem[] NearestNeighbour(BoundablePair <TItem> initBndPair) { double distanceLowerBound = double.PositiveInfinity; BoundablePair <TItem> minPair = null; // initialize search queue var priQ = new PriorityQueue <BoundablePair <TItem> >(); priQ.Add(initBndPair); while (!priQ.IsEmpty() && distanceLowerBound > 0.0) { // pop head of queue and expand one side of pair var bndPair = priQ.Poll(); double pairDistance = bndPair.Distance; /** * 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 (pairDistance >= 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 = pairDistance; minPair = bndPair; } else { /** * 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); }